localgov_directories-3.3.1/tests/src/Functional/FacetsTest.php

tests/src/Functional/FacetsTest.php
<?php

namespace Drupal\Tests\localgov_directories\Functional;

use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\Traits\Core\CronRunTrait;
use Drupal\Tests\node\Traits\NodeCreationTrait;
use Drupal\facets\Entity\Facet;
use Drupal\localgov_directories\Constants as Directory;
use Drupal\localgov_directories\Entity\LocalgovDirectoriesFacets;
use Drupal\localgov_directories\Entity\LocalgovDirectoriesFacetsType;
use Drupal\node\NodeInterface;

/**
 * Tests facets on a directory channel as a filter.
 *
 * @group localgov_directories
 */
class FacetsTest extends BrowserTestBase {

  use NodeCreationTrait;
  use CronRunTrait;

  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

  /**
   * Modules to enable.
   *
   * @var array
   */
  protected static $modules = [
    'localgov_search_db',
    'localgov_directories_db',
    'localgov_directories_page',
  ];

  /**
   * Facet labels.
   *
   * Used for reference in each test.
   *
   * @var array
   */
  protected $facetLabels = [];

  /**
   * Facet entities.
   *
   * Used to set facets accross each test.
   *
   * @var array
   */
  protected $facetEntities = [];

  /**
   * Channel node page.
   *
   * @var \Drupal\node\NodeInterface
   */
  protected $channelNode;

  /**
   * Set up users, node and facets.
   */
  protected function setUp(): void {
    parent::setUp();

    $this->drupalPlaceBlock('facet_block:localgov_directories_facets', []);

    // Set up facet types.
    $facet_types = [
      'Group 1 ' . $this->randomMachineName(8),
      'Group 2 ' . $this->randomMachineName(8),
    ];
    foreach ($facet_types as $type_id) {
      $type = LocalgovDirectoriesFacetsType::create([
        'id' => $type_id,
        'label' => $type_id,
      ]);
      $type->save();
      $facet_type_entities[] = $type;
    }

    // Set up facets.
    $facets = [
      [
        'bundle' => $facet_types[0],
        'title' => 'Facet 1 ' . $this->randomMachineName(8),
      ],
      [
        'bundle' => $facet_types[0],
        'title' => 'Facet 2 ' . $this->randomMachineName(8),
      ],
      [
        'bundle' => $facet_types[1],
        'title' => 'Facet 3' . $this->randomMachineName(8),
      ],
      [
        'bundle' => $facet_types[1],
        'title' => 'Facet 4 ' . $this->randomMachineName(8),
      ],
    ];
    foreach ($facets as $facet_item) {
      $facet = LocalgovDirectoriesFacets::create($facet_item);
      $facet->save();
      $this->facetEntities[] = $facet;
    }
    $this->facetLabels = array_column($facets, 'title');

    // Set up a directory channel and assign the facets to it.
    $body = [
      'value' => 'Science is the search for truth, that is the effort to understand the world: it involves the rejection of bias, of dogma, of revelation, but not the rejection of morality.',
      'summary' => 'One of the greatest joys known to man is to take a flight into ignorance in search of knowledge.',
    ];

    $this->channelNode = $this->createNode([
      'title' => 'Directory channel',
      'type' => 'localgov_directory',
      'status' => NodeInterface::PUBLISHED,
      'body' => $body,
      'localgov_directory_channel_types' => [
        [
          'target_id' => 'localgov_directories_page',
        ],
      ],
      'localgov_directory_facets_enable' => [
        [
          'target_id' => $facet_types[0],
        ],
        [
          'target_id' => $facet_types[1],
        ],
      ],
    ]);
  }

  /**
   * Test facets filter with And groups.
   *
   * Verifies that the correct entries are visible using an OR filter within
   * facet groups and a AND filter accross the groups.
   */
  public function testFacetsGroupFilters() {

    $node_titles_w_nid = $this->createAtestDirectory();
    $node_titles = array_values($node_titles_w_nid);

    // Run cron so the directory entries are indexed.
    $this->cronRun();

    // Check facets and check the right entries are shown.
    $directory_url = $this->channelNode->toUrl()->toString();
    $this->drupalGet($directory_url);

    // Initially all four should be available.
    $this->assertSession()->pageTextContains($node_titles[0]);
    $this->assertSession()->pageTextContains($node_titles[1]);
    $this->assertSession()->pageTextContains($node_titles[2]);
    $this->assertSession()->pageTextContains($node_titles[3]);

    // Facet 1.
    // Click facet 1, should show entry 1, 3 and 4.
    $this->getSession()->getPage()->clickLink($this->facetLabels[0]);
    $this->assertSession()->pageTextContains($node_titles[0]);
    $this->assertSession()->pageTextNotContains($node_titles[1]);
    $this->assertSession()->pageTextContains($node_titles[2]);
    $this->assertSession()->pageTextContains($node_titles[3]);

    // Facet 1 OR Facet 2.
    // Click facet 2 (with 1 still clicked), should show entry 1, 2, 3 and 4.
    $this->getSession()->getPage()->clickLink($this->facetLabels[1]);
    $this->assertSession()->pageTextContains($node_titles[0]);
    $this->assertSession()->pageTextContains($node_titles[1]);
    $this->assertSession()->pageTextContains($node_titles[2]);
    $this->assertSession()->pageTextContains($node_titles[3]);

    // Facet 1 AND Facet 3.
    // Click facet 2 to deselect, click facet 3 (with 1 still clicked),
    // should show entry 3 and 4.
    $this->getSession()->getPage()->clickLink($this->facetLabels[1]);
    $this->getSession()->getPage()->clickLink($this->facetLabels[2]);
    $this->assertSession()->pageTextNotContains($node_titles[0]);
    $this->assertSession()->pageTextNotContains($node_titles[1]);
    $this->assertSession()->pageTextContains($node_titles[2]);
    $this->assertSession()->pageTextContains($node_titles[3]);

    // Facet 1 AND (Facet 3 OR Facet 4).
    // Click facet 4 (with 1 and 3 still clicked),
    // should show entry 3 and 4.
    $this->getSession()->getPage()->clickLink($this->facetLabels[3]);
    $this->assertSession()->pageTextNotContains($node_titles[0]);
    $this->assertSession()->pageTextNotContains($node_titles[1]);
    $this->assertSession()->pageTextContains($node_titles[2]);
    $this->assertSession()->pageTextContains($node_titles[3]);

    // Facet 1 AND Facet 4.
    // Click facet 3 to deselect (with 1 and 4 still clicked),
    // should show entry 4 only.
    $this->getSession()->getPage()->clickLink($this->facetLabels[2]);
    $this->assertSession()->pageTextNotContains($node_titles[0]);
    $this->assertSession()->pageTextNotContains($node_titles[1]);
    $this->assertSession()->pageTextNotContains($node_titles[2]);
    $this->assertSession()->pageTextContains($node_titles[3]);

    // (Facet 1 OR Facet 2) AND (Facet 3 OR Facet 4).
    // Click facet 2 and 3 (with 1 and 4 still clicked),
    // all facets selected, but should only show entry 3 and 4.
    $this->getSession()->getPage()->clickLink($this->facetLabels[1]);
    $this->getSession()->getPage()->clickLink($this->facetLabels[2]);
    $this->assertSession()->pageTextNotContains($node_titles[0]);
    $this->assertSession()->pageTextNotContains($node_titles[1]);
    $this->assertSession()->pageTextContains($node_titles[2]);
    $this->assertSession()->pageTextContains($node_titles[3]);
  }

  /**
   * Test facet selection shows possible facets that could be selected.
   *
   * Verifies that when facets are selected, facets that would offer a possible
   * selection are visible and not hidden. This occurs due to the way facets are
   * generated from the result set. Since each facet group is an OR, if there
   * are entries that could be shown by selecting OR in the group whilst
   * applying the AND filter from the other groups, they need to be selectable.
   */
  public function testFacetSearchShowsAccessibleFacet() {

    // Set up some directory entries .
    $directory_nodes = [
      // Entry 1 has facet 1 and 3.
      [
        'title' => 'Entry 1 ' . $this->randomMachineName(8),
        'type' => 'localgov_directories_page',
        'body' => [
          'value' => 'Contains facet 1 and facet 3.',
        ],
        'status' => NodeInterface::PUBLISHED,
        'localgov_directory_channels' => [
          [
            'target_id' => $this->channelNode->id(),
          ],
        ],
        'localgov_directory_facets_select' => [
          [
            'target_id' => $this->facetEntities[0]->id(),
          ],
          [
            'target_id' => $this->facetEntities[2]->id(),
          ],
        ],
      ],
      [
        // Entry 2 has facet 1 and 4.
        'title' => 'Entry 2 ' . $this->randomMachineName(8),
        'type' => 'localgov_directories_page',
        'body' => [
          'value' => 'Contains facet 1 and facet 4.',
        ],
        'status' => NodeInterface::PUBLISHED,
        'localgov_directory_channels' => [
          [
            'target_id' => $this->channelNode->id(),
          ],
        ],
        'localgov_directory_facets_select' => [
          [
            'target_id' => $this->facetEntities[0]->id(),
          ],
          [
            'target_id' => $this->facetEntities[3]->id(),
          ],
        ],
      ],
      [
        // Entry 3 has facet 2 only.
        'title' => 'Entry 3 ' . $this->randomMachineName(8),
        'type' => 'localgov_directories_page',
        'body' => [
          'value' => 'Contains facet 2 only.',
        ],
        'status' => NodeInterface::PUBLISHED,
        'localgov_directory_channels' => [
          [
            'target_id' => $this->channelNode->id(),
          ],
        ],
        'localgov_directory_facets_select' => [
          [
            'target_id' => $this->facetEntities[1]->id(),
          ],
        ],
      ],
      [
        // Entry 4 has facet 2 and 4.
        'title' => 'Entry 4 ' . $this->randomMachineName(8),
        'type' => 'localgov_directories_page',
        'body' => [
          'value' => 'Contains facet 2 and facet 4.',
        ],
        'status' => NodeInterface::PUBLISHED,
        'localgov_directory_channels' => [
          [
            'target_id' => $this->channelNode->id(),
          ],
        ],
        'localgov_directory_facets_select' => [
          [
            'target_id' => $this->facetEntities[1]->id(),
          ],
          [
            'target_id' => $this->facetEntities[3]->id(),
          ],
        ],
      ],
    ];

    foreach ($directory_nodes as $node) {
      $this->createNode($node);
    }

    // Run cron so the directory entries are indexed.
    $this->cronRun();

    // Check facets and check the right entries are shown.
    $directory_url = $this->channelNode->toUrl()->toString();
    $this->drupalGet($directory_url);

    // Click facet 1.
    // Applies condition entries have facet 1.
    // For each facet group, we are testing for possible facets in each group,
    // Eg. In group 2 we look for facets which would apply with facet 1 from
    // group 1 also selected.
    // Show facets where entries would show for:-
    // - group 1 AND no restriction.
    // - group 2 AND facet 1.
    $this->getSession()->getPage()->clickLink($this->facetLabels[0]);

    // Assert that facets 1, 2, 3 and 4 are visible.
    // Because entry 2 has facet 2 which is in the same group as facet 1,
    // user could click on facet 2 as an OR condition even though entry 2
    // is not visible. Facet 4 will be visible as entry 2 has facet 1 and 4.
    $this->assertSession()->pageTextContains($this->facetLabels[0]);
    $this->assertSession()->pageTextContains($this->facetLabels[1]);
    $this->assertSession()->pageTextContains($this->facetLabels[2]);
    $this->assertSession()->pageTextContains($this->facetLabels[3]);

    // Click facet 3.
    // Applies condition entries have facet 1 AND facet 3.
    // Now each group will have a filter applied, all facets from group 1 which
    // would apply when facet 3 is selected, and all facets from group 2 which
    // would apply when facet 1 is selected, and then the results are combined.
    // Show facets where entries would show for:-
    // - group 1 AND facet 3.
    // - group 2 AND facet 1.
    $this->getSession()->getPage()->clickLink($this->facetLabels[2]);

    // Assert that facets 1, 3 and 4 are visible (2 should be hidden).
    // Since the AND condition that is now applied from facet 3 will
    // eliminate entry 2, so appling it would have no effect. Facet 4 will still
    // be visible as Entry 2 has facet 1 and facet 4, so user could click on
    // on facet 4 and see entry 2.
    $this->assertSession()->pageTextContains($this->facetLabels[0]);
    $this->assertSession()->pageTextNotContains($this->facetLabels[1]);
    $this->assertSession()->pageTextContains($this->facetLabels[2]);
    $this->assertSession()->pageTextContains($this->facetLabels[3]);

    // Click facet 4.
    // Applies condition entries have facet 1 AND (facet 3 OR facet 4).
    // Show facets where entries would show for:-
    // - group 1 AND (facet 3 or facet 4).
    // - group 2 AND facet 1.
    $this->getSession()->getPage()->clickLink($this->facetLabels[3]);

    // Assert that facets 1, 2, 3 and 4 are visible.
    // Since entry 4 has facet 2 and facet 4, when the AND condition is applied
    // from the second facet group (facets 3 & 4) this will allow facet 2 to be
    // selected as it selected it would now produce a valid result.
    $this->assertSession()->pageTextContains($this->facetLabels[0]);
    $this->assertSession()->pageTextContains($this->facetLabels[1]);
    $this->assertSession()->pageTextContains($this->facetLabels[2]);
    $this->assertSession()->pageTextContains($this->facetLabels[3]);

    // Click to deselect facet 1 and 3 and then click to select facet 2.
    // Applies condition entries have facet 2 AND facet 4.
    // Show facets where entries would show for:-
    // - group 1 AND facet 4.
    // - group 2 AND facet 2.
    $this->getSession()->getPage()->clickLink($this->facetLabels[0]);
    $this->getSession()->getPage()->clickLink($this->facetLabels[2]);
    $this->getSession()->getPage()->clickLink($this->facetLabels[1]);

    // Assert that facets 1, 2 and 4 are visible (3 should be hidden).
    // Since the AND condition from the first facet group will only apply to
    // facet 4 and the AND condition from the second group will apply to facet 1
    // OR facet 2 (entry 4 has facets 2 & 4, not shown entry 2 has facet 1 & 3
    // so facet 1 is reachable and will genrate a valid result).
    $this->assertSession()->pageTextContains($this->facetLabels[0]);
    $this->assertSession()->pageTextContains($this->facetLabels[1]);
    $this->assertSession()->pageTextNotContains($this->facetLabels[2]);
    $this->assertSession()->pageTextContains($this->facetLabels[3]);

    // Click to deselect facet 4.
    // Applies conditions entries have facet 2.
    // Show facets where entries would show for:-
    // - group 1 AND no restriction.
    // - group 2 AND facet 2.
    $this->getSession()->getPage()->clickLink($this->facetLabels[3]);

    // Assert that facet 1, 2 and 4 are visible (3 should be hidden).
    // Since no AND condition applies from the second facet group, facet 1
    // can be potentially selected in an OR group with facet 2 as the hidden
    // entry 1 has facet 1. The And condition from the first group with facet 2
    // prevents facet 3 from being reachable, as no entries have facet 2 and 3.
    $this->assertSession()->pageTextContains($this->facetLabels[0]);
    $this->assertSession()->pageTextContains($this->facetLabels[1]);
    $this->assertSession()->pageTextNotContains($this->facetLabels[2]);
    $this->assertSession()->pageTextContains($this->facetLabels[3]);
  }

  /**
   * Tests setup of the Facets form checkbox widget.
   */
  public function testFacetsFormWidget(): void {

    // Setup the Facets form checkbox widget (AKA "Checkboxes (inside form)")
    // for directory facets.
    $this->container->get('module_installer')->install(['facets_form']);

    $dir_facet = Facet::load(Directory::FACET_CONFIG_ENTITY_ID);
    $dir_facet->setOnlyVisibleWhenFacetSourceIsVisible(FALSE);
    $dir_facet->setWidget('facets_form_checkbox');
    $dir_facet->save();
    $this->drupalPlaceBlock(Directory::FACETS_FORM_DIR_FACET_BLOCK_PLUGIN_ID);

    $this->createAtestDirectory();

    // Run cron so the directory entries are indexed.
    $this->cronRun();

    // Check presence of facet checkboxes within a form.
    $directory_url = $this->channelNode->toUrl()->toString();
    $this->drupalGet($directory_url);

    $assert = $this->assertSession();
    $facets_form = $assert->elementExists('css', 'form#facets-form');
    $assert->elementExists('css', 'input#edit-localgov-directories-facets-1[type=checkbox]', $facets_form);
  }

  /**
   * Sets up a test directory.
   *
   * Creates a directory complete with a 4 directory pages assigned to various
   * LocalGov Directory facet values.
   *
   * @return array
   *   A list of node titles keyed by their node ids.
   */
  public function createAtestDirectory(): array {

    // Set up some directory entries.
    $directory_node_values = [
      // Entry 1 has facet 1 only.
      [
        'title' => 'Entry 1 ' . $this->randomMachineName(8),
        'type' => 'localgov_directories_page',
        'status' => NodeInterface::PUBLISHED,
        'localgov_directory_channels' => [
          [
            'target_id' => $this->channelNode->id(),
          ],
        ],
        'localgov_directory_facets_select' => [
          [
            'target_id' => $this->facetEntities[0]->id(),
          ],
        ],
      ],
      [
        // Entry 2 has facet 2 only.
        'title' => 'Entry 2 ' . $this->randomMachineName(8),
        'type' => 'localgov_directories_page',
        'status' => NodeInterface::PUBLISHED,
        'localgov_directory_channels' => [
          [
            'target_id' => $this->channelNode->id(),
          ],
        ],
        'localgov_directory_facets_select' => [
          [
            'target_id' => $this->facetEntities[1]->id(),
          ],
        ],
      ],
      // Entry 3 has facet 1 and 3.
      [
        'title' => 'Entry 3 ' . $this->randomMachineName(8),
        'type' => 'localgov_directories_page',
        'status' => NodeInterface::PUBLISHED,
        'localgov_directory_channels' => [
          [
            'target_id' => $this->channelNode->id(),
          ],
        ],
        'localgov_directory_facets_select' => [
          [
            'target_id' => $this->facetEntities[0]->id(),
          ],
          [
            'target_id' => $this->facetEntities[2]->id(),
          ],
        ],
      ],
      // Entry 4 has all facets.
      [
        'title' => 'Entry 4 ' . $this->randomMachineName(8),
        'type' => 'localgov_directories_page',
        'status' => NodeInterface::PUBLISHED,
        'localgov_directory_channels' => [
          [
            'target_id' => $this->channelNode->id(),
          ],
        ],
        'localgov_directory_facets_select' => [
          [
            'target_id' => $this->facetEntities[0]->id(),
          ],
          [
            'target_id' => $this->facetEntities[1]->id(),
          ],
          [
            'target_id' => $this->facetEntities[2]->id(),
          ],
          [
            'target_id' => $this->facetEntities[3]->id(),
          ],
        ],
      ],
    ];

    foreach ($directory_node_values as $key => $node_values) {
      $new_node = $this->createNode($node_values);
      $directory_node_values[$key]['nid'] = $new_node->id();
    }

    // Get titles for comparison.
    $node_titles = array_column($directory_node_values, 'title', 'nid');

    return $node_titles;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc