You are here

LinkitAutocompleteTest.php in Linkit 8.5

File

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

namespace Drupal\Tests\linkit\Kernel;

use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Html;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\entity_test\Entity\EntityTestMul;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\linkit\Controller\AutocompleteController;
use Drupal\linkit\Entity\Profile;
use Symfony\Component\HttpFoundation\Request;

/**
 * Tests the linkit autocomplete functionality.
 *
 * @group linkit
 */
class LinkitAutocompleteTest extends LinkitKernelTestBase {

  /**
   * Modules to enable.
   *
   * @var array
   */
  public static $modules = [
    'entity_test',
    'language',
  ];

  /**
   * The linkit profile.
   *
   * @var \Drupal\Linkit\ProfileInterface
   */
  protected $linkitProfile;

  /**
   * The matcher manager.
   *
   * @var \Drupal\linkit\MatcherManager
   */
  protected $matcherManager;

  /**
   * The added languages.
   *
   * @var array
   */
  protected $langcodes;

  /**
   * {@inheritdoc}
   */
  protected function setUp() {
    parent::setUp();

    // Create user 1 who has special permissions.
    $this
      ->createUser();
    \Drupal::currentUser()
      ->setAccount($this
      ->createUser([], [
      'view test entity',
    ]));
    \Drupal::service('router.builder')
      ->rebuild();
    $this
      ->installEntitySchema('user');
    $this
      ->installEntitySchema('entity_test');
    $this
      ->installEntitySchema('entity_test_mul');
    $this->matcherManager = $this->container
      ->get('plugin.manager.linkit.matcher');
    $this->linkitProfile = $this
      ->createProfile();
  }

  /**
   * Tests that inaccessible entities isn't included in the results.
   */
  public function testAutocompletionAccess() {

    /** @var \Drupal\linkit\MatcherInterface $plugin */
    $plugin = $this->matcherManager
      ->createInstance('entity:entity_test');
    $this->linkitProfile
      ->addMatcher($plugin
      ->getConfiguration());
    $this->linkitProfile
      ->save();
    $entity_1 = EntityTest::create([
      'name' => 'no_forbid_access',
    ]);
    $entity_1
      ->save();
    $entity_2 = EntityTest::create([
      'name' => 'forbid_access',
    ]);
    $entity_2
      ->save();
    $suggestions = $this
      ->getAutocompleteResult('forbid');
    $this
      ->assertTrue(count($suggestions) == 1, 'Autocomplete returned the expected amount of suggestions.');
    $this
      ->assertSame($entity_1
      ->label(), $suggestions[0]['label'], 'Autocomplete did not include the inaccessible entity.');
  }

  /**
   * Tests that 'front' adds the front page match.
   */
  public function testAutocompletionFront() {

    /** @var \Drupal\linkit\MatcherInterface $plugin */
    $plugin = $this->matcherManager
      ->createInstance('front_page');
    $this->linkitProfile
      ->addMatcher($plugin
      ->getConfiguration());
    $this->linkitProfile
      ->save();
    $data = $this
      ->getAutocompleteResult('front');
    $this
      ->assertSame('Front page', $data[0]['label'], 'Autocomplete returned the front page suggestion.');
  }

  /**
   * Tests the autocomplete with an email address.
   */
  public function testAutocompletionEmail() {

    /** @var \Drupal\linkit\MatcherInterface $plugin */
    $plugin = $this->matcherManager
      ->createInstance('email');
    $this->linkitProfile
      ->addMatcher($plugin
      ->getConfiguration());
    $this->linkitProfile
      ->save();
    $email = 'drupal@example.com';
    $data = $this
      ->getAutocompleteResult($email);
    $this
      ->assertSame((string) new FormattableMarkup('E-mail @email', [
      '@email' => $email,
    ]), $data[0]['label'], 'Autocomplete returned email suggestion.');
    $this
      ->assertSame('mailto:' . $email, $data[0]['path'], 'Autocomplete returned email suggestion with an mailto href.');
  }

  /**
   * Tests autocompletion in general.
   */
  public function testAutocompletion() {

    /** @var \Drupal\linkit\MatcherInterface $plugin */
    $plugin = $this->matcherManager
      ->createInstance('entity:entity_test');
    $this->linkitProfile
      ->addMatcher($plugin
      ->getConfiguration());
    $this->linkitProfile
      ->save();
    $entity_1 = EntityTest::create([
      'name' => 'Barbar',
    ]);
    $entity_1
      ->save();
    $entity_2 = EntityTest::create([
      'name' => 'Foobar',
    ]);
    $entity_2
      ->save();
    $entity_3 = EntityTest::create([
      'name' => 'Basbar',
    ]);
    $entity_3
      ->save();

    // Search for something that doesn't exists.
    $data = $this
      ->getAutocompleteResult('no_suggestions');
    $this
      ->assertTrue(count($data) == 1, 'Autocomplete returned the expected amount of suggestions.');
    $this
      ->assertSame(Html::escape('no_suggestions'), $data[0]['label'], 'Autocomplete returned the "no result" suggestion.');

    // Search for something that exists one time.
    $data = $this
      ->getAutocompleteResult('bas');
    $this
      ->assertTrue(count($data) == 1, 'Autocomplete returned the expected amount of suggestions.');
    $this
      ->assertSame(Html::escape($entity_3
      ->label()), $data[0]['label'], 'Autocomplete returned the matching entity');

    // Search for something that exists three times.
    $data = $this
      ->getAutocompleteResult('bar');
    $this
      ->assertTrue(count($data) == 3, 'Autocomplete returned the expected amount of suggestions.');
    $this
      ->assertSame(Html::escape($entity_1
      ->label()), $data[0]['label'], 'Autocomplete returned the first matching entity.');
    $this
      ->assertSame(Html::escape($entity_3
      ->label()), $data[1]['label'], 'Autocomplete returned the second matching entity.');
    $this
      ->assertSame(Html::escape($entity_2
      ->label()), $data[2]['label'], 'Autocomplete returned the third matching entity.');

    // Search for something with an empty string.
    $data = $this
      ->getAutocompleteResult('');
    $this
      ->assertEmpty(count($data), 'Autocomplete did not return any suggestions.');
  }

  /**
   * Tests autocompletion with results limit.
   */
  public function testAutocompletionWithLimit() {

    /** @var \Drupal\linkit\MatcherInterface $plugin */
    $plugin = $this->matcherManager
      ->createInstance('entity:entity_test');
    $configuration = $plugin
      ->getConfiguration();
    $configuration['settings']['limit'] = 2;
    $this->linkitProfile
      ->addMatcher($configuration);
    $this->linkitProfile
      ->save();
    $entity_1 = EntityTest::create([
      'name' => 'foo 1',
    ]);
    $entity_1
      ->save();
    $entity_2 = EntityTest::create([
      'name' => 'foo 2',
    ]);
    $entity_2
      ->save();
    $entity_3 = EntityTest::create([
      'name' => 'foo 3',
    ]);
    $entity_3
      ->save();
    $data = $this
      ->getAutocompleteResult('foo');
    $this
      ->assertTrue(count($data) == 2, 'Autocomplete returned the expected amount of suggestions.');
  }

  /**
   * Tests autocompletion with translated entities.
   */
  public function testAutocompletionTranslations() {

    /** @var \Drupal\linkit\MatcherInterface $plugin */
    $plugin = $this->matcherManager
      ->createInstance('entity:entity_test_mul');
    $this->linkitProfile
      ->addMatcher($plugin
      ->getConfiguration());
    $this->linkitProfile
      ->save();
    $this
      ->setupLanguages();
    $entity = EntityTestMul::create([
      'name' => 'Barbar',
    ]);

    // Copy the array and shift the default language.
    $translations = $this->langcodes;
    array_shift($translations);
    foreach ($translations as $langcode) {
      $entity
        ->addTranslation($langcode, [
        'name' => 'Barbar ' . $langcode,
      ]);
    }
    $entity
      ->save();
    foreach ($this->langcodes as $langcode) {
      $this
        ->config('system.site')
        ->set('default_langcode', $langcode)
        ->save();
      $data = $this
        ->getAutocompleteResult('bar');
      $this
        ->assertTrue(count($data) == 1, 'Autocomplete returned the expected amount of suggestions.');
      $this
        ->assertSame($entity
        ->getTranslation($langcode)
        ->label(), $data[0]['label'], 'Autocomplete returned the "no results."');
    }
  }

  /**
   * Returns the result of an Linkit autocomplete request.
   *
   * @param string $input
   *   The label of the entity to query by.
   *
   * @return array
   *   An array of suggestions.
   */
  protected function getAutocompleteResult($input) {
    $request = Request::create('linkit/autocomplete/' . $this->linkitProfile
      ->id());
    $request->query
      ->set('q', $input);
    $controller = AutocompleteController::create($this->container);
    $result = Json::decode($controller
      ->autocomplete($request, $this->linkitProfile
      ->id())
      ->getContent());
    return $result['suggestions'];
  }

  /**
   * Creates a profile based on default settings.
   *
   * @param array $settings
   *   (optional) An associative array of settings for the profile, as used in
   *   entity_create(). Override the defaults by specifying the key and value
   *   in the array
   *
   *   The following defaults are provided:
   *   - label: Random string.
   *
   * @return \Drupal\linkit\ProfileInterface
   *   The created profile entity.
   *
   * @todo Do a trait of this?
   */
  protected function createProfile(array $settings = []) {

    // Populate defaults array.
    $settings += [
      'id' => mb_strtolower($this
        ->randomMachineName()),
      'label' => $this
        ->randomMachineName(),
    ];
    $profile = Profile::create($settings);
    $profile
      ->save();
    return $profile;
  }

  /**
   * Returns the "no results" suggestion.
   *
   * @return array
   *   An array with a fixed value of no results.
   *
   * @todo Should this use some kind of t() function?
   */
  protected function noResults() {
    return [
      'title' => 'No results',
    ];
  }

  /**
   * Adds additional languages.
   */
  protected function setupLanguages() {
    $this->langcodes = [
      'sv',
      'da',
      'fi',
    ];
    foreach ($this->langcodes as $langcode) {
      ConfigurableLanguage::createFromLangcode($langcode)
        ->save();
    }
    array_unshift($this->langcodes, \Drupal::languageManager()
      ->getDefaultLanguage()
      ->getId());
  }

}

Classes

Namesort descending Description
LinkitAutocompleteTest Tests the linkit autocomplete functionality.