You are here

ViewsTest.php in Search API Autocomplete 8

File

tests/src/Kernel/ViewsTest.php
View source
<?php

namespace Drupal\Tests\search_api_autocomplete\Kernel;

use Drupal\KernelTests\KernelTestBase;
use Drupal\search_api\Query\ConditionInterface;
use Drupal\search_api_autocomplete\Entity\Search;
use Drupal\search_api_autocomplete\Search\SearchPluginManager;
use Drupal\search_api_autocomplete\Utility\PluginHelper;
use Drupal\views\Entity\View;

/**
 * Tests Views integration of the Autocomplete module.
 *
 * @group search_api_autocomplete
 */
class ViewsTest extends KernelTestBase {

  /**
   * {@inheritdoc}
   */
  public static $modules = [
    'entity_test',
    'field',
    'search_api_autocomplete',
    'search_api_autocomplete_test',
    'search_api',
    'search_api_test',
    'search_api_test_example_content',
    'system',
    'text',
    'user',
    'views',
  ];

  /**
   * {@inheritdoc}
   */
  protected function setUp() {
    parent::setUp();
    $this
      ->installEntitySchema('entity_test_mulrev_changed');
    $this
      ->installEntitySchema('search_api_task');
    $this
      ->installEntitySchema('user');
    $this
      ->installSchema('search_api', [
      'search_api_item',
    ]);
    $this
      ->installConfig('search_api');
    $this
      ->installConfig('search_api_test_example_content');

    // Do not use a batch for tracking the initial items after creating an
    // index when running the tests via the GUI. Otherwise, it seems Drupal's
    // Batch API gets confused and the test fails.
    if (php_sapi_name() != 'cli') {
      \Drupal::state()
        ->set('search_api_use_tracking_batch', FALSE);
    }
  }

  /**
   * Tests that valid search plugin definitions are created for search views.
   */
  public function testSearchPlugin() {
    $index_id = 'autocomplete_search_index';
    $plugin_helper = $this->container
      ->get('search_api_autocomplete.plugin_helper');
    $plugins = $plugin_helper
      ->createSearchPluginsForIndex($index_id);
    $view_id = 'views:search_api_autocomplete_test_view';
    $this
      ->assertArrayNotHasKey($view_id, $plugins);
    $this
      ->installConfig('search_api_autocomplete_test');

    // To avoid getting the cached derivatives from the Views search plugin
    // deriver, we unfortunately need to rebuild the search plugin manager. This
    // is probably the simplest way to do it, without too many side effects.
    $search_plugin_manager = new SearchPluginManager($this->container
      ->get('container.namespaces'), $this->container
      ->get('cache.discovery'), $this->container
      ->get('module_handler'));
    $plugin_helper = new PluginHelper($this->container
      ->get('plugin.manager.search_api_autocomplete.suggester'), $search_plugin_manager);
    $plugins = $plugin_helper
      ->createSearchPluginsForIndex($index_id);
    $this
      ->assertArrayHasKey($view_id, $plugins);

    /** @var \Drupal\search_api_autocomplete\Search\SearchPluginInterface $plugin */
    $plugin = $plugins[$view_id];
    $this
      ->assertEquals('Search API Autocomplete Test view', $plugin
      ->label());
    $this
      ->assertEquals('Search views', $plugin
      ->getGroupLabel());
    $this
      ->assertEquals('Searches provided by Views', $plugin
      ->getGroupDescription());
    $data = [
      'display' => 'page',
      'filter' => 'keys',
    ];
    $query = $plugin
      ->createQuery('foobar', $data);
    $this
      ->assertEquals('foobar', $query
      ->getOriginalKeys());
    $index = $query
      ->getIndex();
    $this
      ->assertEquals($index_id, $index
      ->id());
    $fields = $query
      ->getFulltextFields();
    $all_fulltext_fields = $index
      ->getFulltextFields();
    $fields = isset($fields) ? $fields : $all_fulltext_fields;
    $this
      ->assertEquals($all_fulltext_fields, $fields);
    $query = $plugin
      ->createQuery('', $data);
    $this
      ->assertNull($query
      ->getOriginalKeys());
    $data = [
      'display' => 'page',
      'filter' => 'name',
      'field' => 'name',
    ];
    $query = $plugin
      ->createQuery('foobar', $data);
    $this
      ->assertNull($query
      ->getOriginalKeys());

    // @todo Remove check once we depend on Drupal 9.0+.
    if (method_exists($this, 'assertStringContainsString')) {
      $this
        ->assertStringContainsString('foobar', (string) $query);
    }
    else {
      $this
        ->assertContains('foobar', (string) $query);
    }
    $conditions = $query
      ->getConditionGroup()
      ->getConditions();
    $conditions = $this
      ->collectConditions($conditions);
    $this
      ->assertCount(1, $conditions);
    $condition = $conditions[0];
    $this
      ->assertEquals('name', $condition
      ->getField());
    $this
      ->assertEquals('foobar', $condition
      ->getValue());
    $this
      ->assertEquals($index_id, $query
      ->getIndex()
      ->id());
    $this
      ->assertEquals([
      'name',
    ], $query
      ->getFulltextFields());
  }

  /**
   * Collects conditions from an array of conditions and condition groups.
   *
   * Any information about condition nesting, group operators, etc. is lost.
   * Only makes sense for tests.
   *
   * @param \Drupal\search_api\Query\ConditionInterface[]|\Drupal\search_api\Query\ConditionGroupInterface[] $conditions
   *   An array of conditions and condition groups.
   *
   * @return \Drupal\search_api\Query\ConditionInterface[]
   *   All conditions contained in the given array of conditions and condition
   *   groups.
   */
  protected function collectConditions(array $conditions) {
    $ret = [];
    foreach ($conditions as $condition) {
      if ($condition instanceof ConditionInterface) {
        $ret[] = $condition;
      }
      else {
        $new = $this
          ->collectConditions($condition
          ->getConditions());
        $ret = array_merge($ret, $new);
      }
    }
    return $ret;
  }

  /**
   * Tests that Views forms are altered correctly.
   *
   * @see search_api_autocomplete_form_views_exposed_form_alter()
   *
   * @dataProvider formAlteringDataProvider
   */
  public function testFormAltering($display_id, $expect_altered) {
    $this
      ->installConfig('search_api_autocomplete_test');
    Search::create([
      'id' => 'search_api_autocomplete_test_view',
      'label' => 'Search API Autocomplete Test view',
      'index_id' => 'autocomplete_search_index',
      'suggester_settings' => [
        'live_results' => [],
      ],
      'search_settings' => [
        'views:search_api_autocomplete_test_view' => [
          'displays' => [
            'default' => TRUE,
            'selected' => [
              'page_2',
            ],
          ],
        ],
      ],
    ])
      ->save();
    $view = View::load('search_api_autocomplete_test_view');

    /** @var \Drupal\views\ViewExecutable $executable */
    $executable = $view
      ->getExecutable();
    $this
      ->assertTrue($executable
      ->setDisplay($display_id));
    $executable
      ->initHandlers();

    /** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form */
    $exposed_form = $executable->display_handler
      ->getPlugin('exposed_form');
    $form = $exposed_form
      ->renderExposedForm();
    $keys_element = $form['keys'] ?? $form['keys_wrapper']['keys'];
    if ($expect_altered) {
      $this
        ->assertEquals('search_api_autocomplete', $keys_element['#type']);
    }
    else {
      $this
        ->assertEquals('textfield', $keys_element['#type']);
    }
  }

  /**
   * Provides test data for testFormAltering().
   *
   * @return array
   *   Array of argument arrays for testFormAltering().
   *
   * @see \Drupal\Tests\search_api_autocomplete\Kernel\ViewsTest::testFormAltering()
   */
  public function formAlteringDataProvider() {
    return [
      'do alter' => [
        'page',
        TRUE,
      ],
      "don't alter" => [
        'page_2',
        FALSE,
      ],
    ];
  }

  /**
   * Tests that the deriver works correctly.
   *
   * @see \Drupal\search_api_autocomplete\Plugin\search_api_autocomplete\search\ViewsDeriver
   */
  public function testDeriver() {
    $searches = $this->container
      ->get('plugin.manager.search_api_autocomplete.search')
      ->getDefinitions();
    $expected = [
      'search_api_autocomplete_test',
    ];
    $this
      ->assertEquals($expected, array_keys($searches));
    $this
      ->installConfig('search_api_autocomplete_test');
    $searches = $this->container
      ->get('plugin.manager.search_api_autocomplete.search')
      ->getDefinitions();
    ksort($searches);
    $expected = [
      'search_api_autocomplete_test',
      'views:search_api_autocomplete_test_view',
    ];
    $this
      ->assertEquals($expected, array_keys($searches));
    View::create([
      'id' => 'second_test_view',
      'base_field' => 'search_api_id',
      'base_table' => 'search_api_index_autocomplete_search_index',
      'core' => '8.x',
      'display' => [
        'default' => [
          'display_plugin' => 'default',
          'id' => 'default',
          'display_title' => 'Master',
          'position' => 0,
          'display_options' => [
            'query' => [
              'type' => 'search_api_query',
            ],
          ],
        ],
      ],
    ])
      ->save();
    $searches = $this->container
      ->get('plugin.manager.search_api_autocomplete.search')
      ->getDefinitions();
    ksort($searches);
    $expected = [
      'search_api_autocomplete_test',
      'views:search_api_autocomplete_test_view',
      'views:second_test_view',
    ];
    $this
      ->assertEquals($expected, array_keys($searches));
  }

}

Classes

Namesort descending Description
ViewsTest Tests Views integration of the Autocomplete module.