updated linkit contrib module to last beta version

This commit is contained in:
2018-04-17 14:53:21 +02:00
parent c0fbcb7706
commit 76ff40f8bb
136 changed files with 5138 additions and 3860 deletions
@@ -0,0 +1,54 @@
uuid: 4947dfdc-fca3-41fd-97a8-b9dcdb4d510c
langcode: en
status: true
dependencies:
config:
- filter.format.format_1
module:
- ckeditor
format: format_1
editor: ckeditor
settings:
toolbar:
rows:
-
-
name: Formatting
items:
- Bold
- Italic
-
name: Links
items:
- DrupalLink
- Linkit
- DrupalUnlink
-
name: Lists
items:
- BulletedList
- NumberedList
-
name: Media
items:
- Blockquote
- DrupalImage
-
name: Tools
items:
- Source
plugins:
stylescombo:
styles: ''
language:
language_list: un
linkit:
linkit_profile: test_profile
image_upload:
status: false
scheme: public
directory: inline-images
max_size: ''
max_dimensions:
width: null
height: null
@@ -0,0 +1,53 @@
uuid: fcc983a2-6cfd-44c4-a592-e6573180c2ac
langcode: en
status: true
dependencies:
config:
- filter.format.format_2
module:
- ckeditor
format: format_2
editor: ckeditor
settings:
toolbar:
rows:
-
-
name: Formatting
items:
- Bold
- Italic
-
name: Links
items:
- Linkit
- DrupalUnlink
-
name: Lists
items:
- BulletedList
- NumberedList
-
name: Media
items:
- Blockquote
- DrupalImage
-
name: Tools
items:
- Source
plugins:
stylescombo:
styles: ''
language:
language_list: un
linkit:
linkit_profile: test_profile
image_upload:
status: false
scheme: public
directory: inline-images
max_size: ''
max_dimensions:
width: null
height: null
@@ -0,0 +1,25 @@
uuid: 5600b759-8f91-49fa-88f0-a69f4c8ed440
langcode: en
status: true
dependencies:
config:
- filter.format.format_3
module:
- ckeditor
format: format_3
editor: ckeditor
settings:
toolbar:
rows:
-
-
name: Links
items:
- Linkit
plugins:
stylescombo:
styles: ''
language:
language_list: un
linkit:
linkit_profile: test_profile
@@ -0,0 +1,17 @@
uuid: 3e7bc0b9-3220-4b4d-aa62-e8e0c5c7e8c0
langcode: en
status: true
dependencies: { }
name: 'Format 1'
format: format_1
weight: 0
filters:
filter_html:
id: filter_html
provider: filter
status: true
weight: -86
settings:
allowed_html: '<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type=''1 A I''> <li> <dl> <dt> <dd> <h2 id=''jump-*''> <h3 id> <h4 id> <h5 id> <h6 id>'
filter_html_help: true
filter_html_nofollow: false
@@ -0,0 +1,8 @@
uuid: 69cd7d6b-3c80-4f49-9631-7fbd7b011d5d
langcode: en
status: true
dependencies: { }
name: 'Format 2'
format: format_2
weight: 0
filters: { }
@@ -0,0 +1,17 @@
uuid: ff6b71a0-5051-4857-a0a8-28a670b7317d
langcode: en
status: true
dependencies: { }
name: 'Format 3'
format: format_3
weight: 0
filters:
filter_html:
id: filter_html
provider: filter
status: true
weight: -10
settings:
allowed_html: '<em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type=''1 A I''> <li> <dl> <dt> <dd> <h2 id=''jump-*''> <h3 id> <h4 id> <h5 id> <h6 id>'
filter_html_help: true
filter_html_nofollow: false
@@ -0,0 +1,73 @@
<?php
/**
* @file
* Database fixture for testing the update hooks.
*
* Contains database additions to drupal-8.bare.standard.php.gz for testing the
* update hooks.
*/
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Database\Database;
$connection = Database::getConnection();
// Configuration for linkit profiles.
$configs = [];
$configs[] = Yaml::decode(file_get_contents(__DIR__ . '/linkit.linkit_profile.test_profile.yml'));
$configs[] = Yaml::decode(file_get_contents(__DIR__ . '/linkit.linkit_profile.test_profile_with_imce.yml'));
foreach ($configs as $config) {
$connection->insert('config')
->fields([
'collection',
'name',
'data',
])
->values([
'collection' => '',
'name' => 'linkit.linkit_profile.' . $config['id'],
'data' => serialize($config),
])
->execute();
}
// Configuration for text formats.
$configs = [];
$configs[] = Yaml::decode(file_get_contents(__DIR__ . '/filter.format.format_1.yml'));
$configs[] = Yaml::decode(file_get_contents(__DIR__ . '/filter.format.format_2.yml'));
$configs[] = Yaml::decode(file_get_contents(__DIR__ . '/filter.format.format_3.yml'));
foreach ($configs as $config) {
$connection->insert('config')
->fields([
'collection',
'name',
'data',
])
->values([
'collection' => '',
'name' => 'filter.format.' . $config['format'],
'data' => serialize($config),
])
->execute();
}
// Configuration for editors.
$configs = [];
$configs[] = Yaml::decode(file_get_contents(__DIR__ . '/editor.editor.format_1.yml'));
$configs[] = Yaml::decode(file_get_contents(__DIR__ . '/editor.editor.format_2.yml'));
$configs[] = Yaml::decode(file_get_contents(__DIR__ . '/editor.editor.format_3.yml'));
foreach ($configs as $config) {
$connection->insert('config')
->fields([
'collection',
'name',
'data',
])
->values([
'collection' => '',
'name' => 'editor.editor.' . $config['format'],
'data' => serialize($config),
])
->execute();
}
@@ -0,0 +1,47 @@
uuid: e91c2255-2146-46fb-af58-1b391113c352
langcode: en
status: true
dependencies:
module:
- file
- node
id: test_profile
label: 'Test profile'
description: 'This is a test profile'
attributes:
target:
id: target
weight: 0
settings:
widget_type: simple_checkbox
title:
id: title
weight: 0
settings:
automatic_title: false
accesskey:
id: accesskey
weight: 0
settings: { }
matchers:
fc48c807-2a9c-44eb-b86b-7e134c1aa252:
uuid: fc48c807-2a9c-44eb-b86b-7e134c1aa252
id: 'entity:node'
weight: 0
settings:
result_description: 'by [node:author] | [node:created:medium]'
bundles: { }
group_by_bundle: false
include_unpublished: false
b8d6d672-6377-493f-b492-3cc69511cf17:
uuid: b8d6d672-6377-493f-b492-3cc69511cf17
id: 'entity:file'
weight: 0
settings:
result_description: '[file:path] [file:url]'
bundles: null
group_by_bundle: null
images:
show_dimensions: false
show_thumbnail: false
thumbnail_image_style: null
@@ -0,0 +1,24 @@
uuid: 3cfc827f-07ff-456e-86db-a831e3770a03
langcode: en
status: true
dependencies:
module:
- imce
- node
third_party_settings:
imce:
use: 1
scheme: public
id: test_profile_imce
label: 'Test profile imce'
description: 'This is a test profile with imce settings'
matchers:
556010a3-e317-48b3-b4ed-854c10f4b950:
uuid: 556010a3-e317-48b3-b4ed-854c10f4b950
id: 'entity:node'
weight: 0
settings:
result_description: 'by [node:author] | [node:created:medium]'
bundles: { }
group_by_bundle: false
include_unpublished: false
@@ -1,13 +1,5 @@
# Schema for the configuration files of the Linkit test module.
# Plugin \Drupal\linkit_test\Plugin\Linkit\Attribute\ConfigurableDummyAttribute
linkit.attribute.configurable_dummy_attribute:
type: linkit.attribute
mapping:
dummy_setting:
type: boolean
# Plugin \Drupal\linkit_test\Plugin\Linkit\Matcher\ConfigurableDummyMatcher
linkit.matcher.configurable_dummy_matcher:
type: linkit.matcher
@@ -5,12 +5,12 @@ type: module
# version: VERSION
# core: 8.x
dependencies:
- linkit
- field
- text
- linkit:linkit
- drupal:field
- drupal:text
# Information added by Drupal.org packaging script on 2017-03-21
version: '8.x-4.3'
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-5.0-beta7'
core: '8.x'
project: 'linkit'
datestamp: 1490127367
datestamp: 1520552594
@@ -4,13 +4,3 @@
* @file
* Support module for Linkit testing.
*/
/**
* Implements hook_linkit_attribute_alter().
*/
function linkit_test_linkit_attribute_alter(&$linkit_attribute_info) {
if (isset($linkit_attribute_info['dummyattribute'])) {
$linkit_attribute_info['dummyattribute']['description'] = t('Altered dummy description');
}
}
@@ -1,73 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\linkit_test\Plugin\Linkit\Attribute\ConfigurableDummyAttribute.
*/
namespace Drupal\linkit_test\Plugin\Linkit\Attribute;
use Drupal\Core\Form\FormStateInterface;
use Drupal\linkit\ConfigurableAttributeBase;
/**
* Accesskey attribute.
*
* @Attribute(
* id = "configurable_dummy_attribute",
* label = @Translation("Configurable Dummy Attribute"),
* html_name = "configurabledummyattribute",
* description = @Translation("Configurable Dummy Attribute")
* )
*/
class ConfigurableDummyAttribute extends ConfigurableAttributeBase {
/**
* {@inheritdoc}
*/
public function buildFormElement($default_value) {
return [
'#type' => 'textfield',
'#title' => t('DummyAttribute'),
'#default_value' => $default_value,
'#maxlength' => 255,
'#size' => 40,
];
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return parent::defaultConfiguration() + [
'dummy_setting' => FALSE,
];
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form['dummy_setting'] = [
'#type' => 'checkbox',
'#title' => $this->t('Dummy setting'),
'#default_value' => $this->configuration['dummy_setting'],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['dummy_setting'] = $form_state->getValue('dummy_setting');
}
}
@@ -1,37 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\linkit_test\Plugin\Linkit\Attribute\DummyAttribute.
*/
namespace Drupal\linkit_test\Plugin\Linkit\Attribute;
use Drupal\linkit\AttributeBase;
/**
* Accesskey attribute.
*
* @Attribute(
* id = "dummy_attribute",
* label = @Translation("Dummy Attribute"),
* html_name = "dummyattribute",
* description = @Translation("Dummy Attribute")
* )
*/
class DummyAttribute extends AttributeBase {
/**
* {@inheritdoc}
*/
public function buildFormElement($default_value) {
return [
'#type' => 'textfield',
'#title' => t('DummyAttribute'),
'#default_value' => $default_value,
'#maxlength' => 255,
'#size' => 40,
];
}
}
@@ -1,18 +1,15 @@
<?php
/**
* @file
* Contains \Drupal\linkit_test\Plugin\Linkit\Matcher\ConfigurableDummyMatcher.
*/
namespace Drupal\linkit_test\Plugin\Linkit\Matcher;
use Drupal\Core\Form\FormStateInterface;
use Drupal\linkit\ConfigurableMatcherBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\linkit\Suggestion\DescriptionSuggestion;
use Drupal\linkit\Suggestion\SuggestionCollection;
/**
* Provides test linkit matchers for the configurable_dummy_matcher entity type.
*
* @Matcher(
* id = "configurable_dummy_matcher",
* label = @Translation("Configurable Dummy Matcher"),
@@ -20,17 +17,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class ConfigurableDummyMatcher extends ConfigurableMatcherBase {
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition
);
}
/**
* {@inheritdoc}
*/
@@ -69,15 +55,17 @@ class ConfigurableDummyMatcher extends ConfigurableMatcherBase {
/**
* {@inheritdoc}
*/
public function getMatches($string) {
$matches[] = [
'title' => 'Configurable Dummy Matcher title',
'description' => 'Configurable Dummy Matcher description',
'path' => 'http://example.com',
'group' => 'Configurable Dummy Matcher',
];
public function execute($string) {
$suggestions = new SuggestionCollection();
$suggestion = new DescriptionSuggestion();
$suggestion->setLabel('Configurable Dummy Matcher title')
->setPath('http://example.com')
->setGroup('Configurable Dummy Matcher')
->setDescription('Configurable Dummy Matcher description');
return $matches;
$suggestions->addSuggestion($suggestion);
return $suggestions;
}
}
@@ -1,17 +1,14 @@
<?php
/**
* @file
* Contains \Drupal\linkit_test\Plugin\Linkit\Matcher\DummyMatcher.
*/
namespace Drupal\linkit_test\Plugin\Linkit\Matcher;
use Drupal\linkit\MatcherBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\linkit\Suggestion\SimpleSuggestion;
use Drupal\linkit\Suggestion\SuggestionCollection;
/**
* Provides test linkit matchers for the dummy_matcher entity type.
*
* @Matcher(
* id = "dummy_matcher",
* label = @Translation("Dummy Matcher"),
@@ -22,26 +19,16 @@ class DummyMatcher extends MatcherBase {
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition
);
}
public function execute($string) {
$suggestions = new SuggestionCollection();
$suggestion = new SimpleSuggestion();
$suggestion->setLabel('Dummy Matcher title')
->setPath('http://example.com')
->setGroup('Dummy Matcher');
/**
* {@inheritdoc}
*/
public function getMatches($string) {
$matches[] = [
'title' => 'DummyMatcher title',
'description' => 'DummyMatcher description',
'path' => 'http://example.com',
'group' => 'DummyMatcher',
];
$suggestions->addSuggestion($suggestion);
return $matches;
return $suggestions;
}
}
@@ -0,0 +1,60 @@
<?php
namespace Drupal\Tests\linkit\Functional\Controller;
use Drupal\linkit\Tests\ProfileCreationTrait;
use Drupal\Tests\linkit\Functional\LinkitBrowserTestBase;
/**
* Tests Linkit controller.
*
* @group linkit
*/
class LinkitControllerTest extends LinkitBrowserTestBase {
use ProfileCreationTrait;
/**
* The linkit profile.
*
* @var \Drupal\linkit\ProfileInterface
*/
protected $linkitProfile;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->linkitProfile = $this->createProfile();
}
/**
* Tests the profile route title callback.
*/
public function testProfileTitle() {
$this->drupalLogin($this->adminUser);
$this->drupalGet('/admin/config/content/linkit/manage/' . $this->linkitProfile->id());
$this->assertSession()->pageTextContains('Edit ' . $this->linkitProfile->label() . ' profile');
}
/**
* Tests the matcher route title callback.
*/
public function testMatcherTitle() {
$this->drupalLogin($this->adminUser);
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->container->get('plugin.manager.linkit.matcher')->createInstance('configurable_dummy_matcher');
$matcher_uuid = $this->linkitProfile->addMatcher($plugin->getConfiguration());
$this->linkitProfile->save();
$this->drupalGet('/admin/config/content/linkit/manage/' . $this->linkitProfile->id() . '/matchers/' . $matcher_uuid);
$this->assertSession()->pageTextContains('Edit ' . $plugin->getLabel() . ' matcher');
}
}
@@ -0,0 +1,48 @@
<?php
namespace Drupal\Tests\linkit\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Provides a base class for Linkit functional tests.
*/
abstract class LinkitBrowserTestBase extends BrowserTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = ['linkit', 'linkit_test', 'block'];
/**
* A test user with administrative privileges.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* A user without the 'administer linkit profiles' permission.
*
* @var \Drupal\user\UserInterface
*/
protected $webUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->placeBlock('page_title_block');
$this->placeBlock('local_tasks_block');
$this->placeBlock('local_actions_block');
$this->placeBlock('system_messages_block');
$this->adminUser = $this->drupalCreateUser(['administer linkit profiles']);
$this->webUser = $this->drupalCreateUser();
}
}
@@ -0,0 +1,138 @@
<?php
namespace Drupal\Tests\linkit\Functional;
use Drupal\linkit\Entity\Profile;
use Drupal\linkit\Tests\ProfileCreationTrait;
/**
* Tests adding, listing, updating and deleting matchers on a profile.
*
* @group linkit
*/
class MatcherAdminTest extends LinkitBrowserTestBase {
use ProfileCreationTrait;
/**
* The attribute manager.
*
* @var \Drupal\linkit\MatcherManager
*/
protected $manager;
/**
* The linkit profile.
*
* @var \Drupal\linkit\ProfileInterface
*/
protected $linkitProfile;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->manager = $this->container->get('plugin.manager.linkit.matcher');
$this->linkitProfile = $this->createProfile();
}
/**
* Test the overview page.
*/
public function testOverview() {
$this->drupalLogin($this->adminUser);
$this->drupalGet('/admin/config/content/linkit/manage/' . $this->linkitProfile->id() . '/matchers');
$this->assertSession()->pageTextContains(t('No matchers added.'));
// Make sure the 'Add matcher' action link is present.
$this->assertSession()->linkByHrefExists('/admin/config/content/linkit/manage/' . $this->linkitProfile->id() . '/matchers/add');
}
/**
* Test adding a matcher to a profile.
*/
public function testAdd() {
$this->drupalLogin($this->adminUser);
$this->drupalGet('/admin/config/content/linkit/manage/' . $this->linkitProfile->id() . '/matchers/add');
// Create matcher.
$edit = [];
$edit['plugin'] = 'dummy_matcher';
$this->submitForm($edit, t('Save and continue'));
// Reload the profile.
$this->linkitProfile = Profile::load($this->linkitProfile->id());
$matcher_ids = $this->linkitProfile->getMatchers()->getInstanceIds();
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->linkitProfile->getMatcher(current($matcher_ids));
$this->assertSession()->responseContains(t('Added %label matcher.', ['%label' => $plugin->getLabel()]));
$this->assertSession()->pageTextNotContains(t('No matchers added.'));
}
/**
* Test adding a configurable attribute to a profile.
*/
public function testAddConfigurable() {
$this->drupalLogin($this->adminUser);
$this->drupalGet('/admin/config/content/linkit/manage/' . $this->linkitProfile->id() . '/matchers/add');
// Create configurable matcher.
$edit = [];
$edit['plugin'] = 'configurable_dummy_matcher';
$this->submitForm($edit, t('Save and continue'));
// Reload the profile.
$this->linkitProfile = Profile::load($this->linkitProfile->id());
$matcher_ids = $this->linkitProfile->getMatchers()->getInstanceIds();
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->linkitProfile->getMatcher(current($matcher_ids));
$this->assertSession()->addressEquals('/admin/config/content/linkit/manage/' . $this->linkitProfile->id() . '/matchers/' . $plugin->getUuid());
$this->drupalGet('/admin/config/content/linkit/manage/' . $this->linkitProfile->id() . '/matchers');
$this->assertSession()->pageTextNotContains(t('No matchers added.'));
}
/**
* Test delete a matcher from a profile.
*/
public function testDelete() {
$this->drupalLogin($this->adminUser);
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('dummy_matcher');
$plugin_uuid = $this->linkitProfile->addMatcher($plugin->getConfiguration());
$this->linkitProfile->save();
// Try delete a matcher that is not attached to the profile.
$this->drupalGet('/admin/config/content/linkit/manage/' . $this->linkitProfile->id() . '/matchers/doesntexists/delete');
$this->assertSession()->statusCodeEquals('404');
// Go to the delete page, but press cancel.
$this->drupalGet('/admin/config/content/linkit/manage/' . $this->linkitProfile->id() . '/matchers/' . $plugin_uuid . '/delete');
$this->clickLink(t('Cancel'));
$this->assertSession()->addressEquals('/admin/config/content/linkit/manage/' . $this->linkitProfile->id() . '/matchers');
// Delete the matcher from the profile.
$this->drupalGet('/admin/config/content/linkit/manage/' . $this->linkitProfile->id() . '/matchers/' . $plugin_uuid . '/delete');
$this->submitForm([], t('Confirm'));
$this->assertSession()->responseContains(t('The matcher %plugin has been deleted.', ['%plugin' => $plugin->getLabel()]));
$this->assertSession()->addressEquals('/admin/config/content/linkit/manage/' . $this->linkitProfile->id() . '/matchers');
$this->assertSession()->pageTextContains(t('No matchers added.'));
/** @var \Drupal\linkit\Entity\Profile $updated_profile */
$updated_profile = Profile::load($this->linkitProfile->id());
$this->assertFalse($updated_profile->getMatchers()->has($plugin_uuid), 'The user matcher is deleted from the profile');
}
}
@@ -0,0 +1,128 @@
<?php
namespace Drupal\Tests\linkit\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\linkit\Tests\ProfileCreationTrait;
/**
* Tests creating, loading and deleting profiles.
*
* @group linkit
*/
class ProfileAdminTest extends LinkitBrowserTestBase {
use ProfileCreationTrait;
/**
* Test the overview page.
*/
public function testOverview() {
// Verify that the profile collection page is not accessible for users
// without permission.
$this->drupalLogin($this->webUser);
$this->drupalGet('/admin/config/content/linkit');
$this->assertSession()->statusCodeEquals(403);
$this->drupalLogout();
// Login as an admin user and make sure the collection page is accessible.
$this->drupalLogin($this->adminUser);
$this->drupalGet('/admin/config/content/linkit');
$this->assertSession()->statusCodeEquals(200);
// Make sure the 'Add profile' action link is present.
$this->assertSession()->linkByHrefExists('/admin/config/content/linkit/add');
// Create multiple profiles.
$profiles = [];
$profiles[] = $this->createProfile();
$profiles[] = $this->createProfile();
// Refresh the page.
$this->drupalGet('/admin/config/content/linkit');
$this->assertSession()->statusCodeEquals(200);
// Make sure that there is an edit and a delete operation link for all
// profiles.
foreach ($profiles as $profile) {
$this->assertSession()->linkByHrefExists('/admin/config/content/linkit/manage/' . $profile->id());
$this->assertSession()->linkByHrefExists('/admin/config/content/linkit/manage/' . $profile->id() . '/delete');
}
}
/**
* Creates profile.
*/
public function testProfileCreation() {
$this->drupalLogin($this->adminUser);
// Make sure the profile add page is accessible.
$this->drupalGet('/admin/config/content/linkit/add');
$this->assertSession()->statusCodeEquals(200);
// Create a profile.
$edit = [];
$edit['label'] = Unicode::strtolower($this->randomMachineName());
$edit['id'] = Unicode::strtolower($this->randomMachineName());
$edit['description'] = $this->randomMachineName(16);
$this->submitForm($edit, t('Save and manage matchers'));
// Make sure that the new profile was saved properly.
$this->assertSession()->responseContains(t('Created new profile %label.', ['%label' => $edit['label']]));
$this->drupalGet('/admin/config/content/linkit');
$this->assertSession()->pageTextContains($edit['label']);
}
/**
* Updates a profile.
*/
public function testProfileUpdate() {
$this->drupalLogin($this->adminUser);
// Create a profile.
$profile = $this->createProfile();
// Make sure the profile edit page is accessible.
$this->drupalGet('/admin/config/content/linkit/manage/' . $profile->id());
$this->assertSession()->statusCodeEquals(200);
// Make sure the machine name field is disabled and that we have certain
// elements presented.
$this->assertSession()->elementNotExists('xpath', '//input[not(@disabled) and @name="id"]');
$this->assertSession()->buttonExists('Update profile');
$this->assertSession()->linkByHrefExists('/admin/config/content/linkit/manage/' . $profile->id() . '/delete');
// Update the profile.
$edit = [];
$edit['label'] = $this->randomMachineName();
$edit['description'] = $this->randomMachineName(16);
$this->submitForm($edit, t('Update profile'));
// Make sure that the profile was updated properly.
$this->assertSession()->responseContains(t('Updated profile %label.', ['%label' => $edit['label']]));
$this->drupalGet('/admin/config/content/linkit');
$this->assertSession()->pageTextContains($edit['label']);
}
/**
* Delete a profile.
*/
public function testProfileDelete() {
$this->drupalLogin($this->adminUser);
// Create a profile.
$profile = $this->createProfile();
$this->drupalGet('/admin/config/content/linkit/manage/' . $profile->id() . '/delete');
$this->assertSession()->statusCodeEquals(200);
// Delete the profile.
$this->submitForm([], t('Delete'));
// Make sure that the profile was deleted properly.
$this->assertSession()->responseContains(t('The linkit profile %label has been deleted.', ['%label' => $profile->label()]));
$this->drupalGet('/admin/config/content/linkit');
$this->assertSession()->responseNotContains($profile->label());
}
}
@@ -0,0 +1,320 @@
<?php
namespace Drupal\Tests\linkit\FunctionalJavascript;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\editor\Entity\Editor;
use Drupal\entity_test\Entity\EntityTestMul;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\filter\Entity\FilterFormat;
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\linkit\Tests\ProfileCreationTrait;
use Drupal\node\Entity\NodeType;
/**
* Tests the linkit alterations on the drupallink plugin.
*
* @group linkit
*/
class LinkitDialogTest extends JavascriptTestBase {
use ProfileCreationTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'node',
'ckeditor',
'filter',
'linkit',
'entity_test',
'language',
];
/**
* An instance of the "CKEditor" text editor plugin.
*
* @var \Drupal\ckeditor\Plugin\Editor\CKEditor
*/
protected $ckeditor;
/**
* A linkit profile.
*
* @var \Drupal\linkit\ProfileInterface
*/
protected $linkitProfile;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$matcherManager = $this->container->get('plugin.manager.linkit.matcher');
/** @var \Drupal\linkit\MatcherInterface $plugin */
$this->linkitProfile = $this->createProfile();
$plugin = $matcherManager->createInstance('entity:entity_test_mul');
$this->linkitProfile->addMatcher($plugin->getConfiguration());
$this->linkitProfile->save();
// Create text format, associate CKEditor.
$llama_format = FilterFormat::create([
'format' => 'llama',
'name' => 'Llama',
'weight' => 0,
'filters' => [],
]);
$llama_format->save();
$editor = Editor::create([
'format' => 'llama',
'editor' => 'ckeditor',
]);
$editor->save();
// Create "CKEditor" text editor plugin instance.
$this->ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
// Create a node type for testing.
NodeType::create(['type' => 'page', 'name' => 'page'])->save();
// Create a body field instance for the 'page' node type.
FieldConfig::create([
'field_storage' => FieldStorageConfig::loadByName('node', 'body'),
'bundle' => 'page',
'label' => 'Body',
'settings' => ['display_summary' => TRUE],
'required' => TRUE,
])->save();
// Assign widget settings for the 'default' form mode.
EntityFormDisplay::create([
'targetEntityType' => 'node',
'bundle' => 'page',
'mode' => 'default',
'status' => TRUE,
])->setComponent('body', ['type' => 'text_textarea_with_summary'])->save();
// Customize the configuration.
$this->container->get('plugin.manager.editor')->clearCachedDefinitions();
$this->ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
$this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
$settings = $editor->getSettings();
$settings['plugins']['drupallink']['linkit_enabled'] = TRUE;
$settings['plugins']['drupallink']['linkit_profile'] = $this->linkitProfile->id();
$editor->setSettings($settings);
$editor->save();
$account = $this->drupalCreateUser([
'administer nodes',
'create page content',
'edit own page content',
'use text format llama',
'view test entity',
]);
$this->drupalLogin($account);
}
/**
* Test the link dialog.
*/
public function testLinkDialog() {
$session = $this->getSession();
$web_assert = $this->assertSession();
$page = $session->getPage();
// Adds additional languages.
$langcodes = ['sv', 'da', 'fi'];
foreach ($langcodes as $langcode) {
ConfigurableLanguage::createFromLangcode($langcode)->save();
}
// Create a test entity.
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = EntityTestMul::create(['name' => 'Foo']);
$entity->save();
// Go to node creation page.
$this->drupalGet('node/add/page');
// Wait until the editor has been loaded.
$ckeditor_loaded = $this->getSession()->wait(5000, "jQuery('.cke_contents').length > 0");
$this->assertTrue($ckeditor_loaded, 'The editor has been loaded.');
// Click on the drupallink plugin.
$page->find('css', 'a.cke_button__drupallink')->click();
// Wait for the form to load.
$web_assert->assertWaitOnAjaxRequest();
// Find the href field.
$href_field = $page->findField('attributes[href]');
// Make sure the href field is an autocomplete field.
$href_field->hasAttribute('data-autocomplete-path');
$href_field->hasClass('form-linkit-autocomplete');
$href_field->hasClass('ui-autocomplete-input');
// Make sure all fields are empty.
$this->assertEmpty($href_field->getValue(), 'Href field is empty.');
$this->assertEmptyWithJs('attributes[data-entity-type]');
$this->assertEmptyWithJs('attributes[data-entity-uuid]');
$this->assertEmptyWithJs('attributes[data-entity-substitution]');
$this->assertEmptyWithJs('href_dirty_check');
// Make sure the autocomplete result container is hidden.
$autocomplete_container = $page->find('css', 'ul.linkit-ui-autocomplete');
$this->assertFalse($autocomplete_container->isVisible());
// Trigger a keydown event to active a autocomplete search.
$href_field->keyDown('f');
// Wait for the results to load.
$this->getSession()->wait(5000, "jQuery('.linkit-result-line.ui-menu-item').length > 0");
// Make sure the autocomplete result container is visible.
$this->assertTrue($autocomplete_container->isVisible());
// Find all the autocomplete results.
$results = $page->findAll('css', '.linkit-result-line.ui-menu-item');
$this->assertEquals(1, count($results), 'Found autocomplete result');
// Find the first result and click it.
$page->find('xpath', '//li[contains(@class, "linkit-result-line") and contains(@class, "ui-menu-item")][1]')->click();
// Make sure the linkit field field is populated with the node url.
$this->assertEquals($entity->toUrl()->toString(), $href_field->getValue(), 'The href field is populated with the node url.');
// Make sure all other fields are populated.
$this->assertEqualsWithJs('attributes[data-entity-type]', $entity->getEntityTypeId());
$this->assertEqualsWithJs('attributes[data-entity-uuid]', $entity->uuid());
$this->assertEqualsWithJs('attributes[data-entity-substitution]', 'canonical');
$this->assertEqualsWithJs('href_dirty_check', $entity->toUrl()->toString());
// Save the dialog input.
$this->click('.editor-link-dialog button:contains("Save")');
// Wait for the dialog to close.
$web_assert->assertWaitOnAjaxRequest();
$fields = [
'data-entity-type' => $entity->getEntityTypeId(),
'data-entity-uuid' => $entity->uuid(),
'data-entity-substitution' => 'canonical',
'href' => $entity->toUrl()->toString(),
];
foreach ($fields as $attribute => $value) {
$link_attribute = $this->getLinkAttributeFromEditor($attribute);
$this->assertEquals($value, $link_attribute, 'The link contain an attribute by the name of "' . $attribute . '" with a value of "' . $value . '"');
}
// Select the link in the editor.
$javascript = <<<JS
(function(){
var editor = window.CKEDITOR.instances['edit-body-0-value'];
console.log(editor);
var element = editor.document.findOne( 'a' );
editor.getSelection().selectElement( element );
})()
JS;
$session->executeScript($javascript);
// Click on the drupallink plugin.
$page->find('css', 'a.cke_button__drupallink')->click();
// Wait for the form to load.
$web_assert->assertWaitOnAjaxRequest();
// Find the href field.
$href_field = $page->findField('attributes[href]');
$this->assertEquals($entity->toUrl()->toString(), $href_field->getValue(), 'Href field contains the node url when edit.');
// Make sure all other fields are populated when editing a link.
$this->assertEqualsWithJs('attributes[data-entity-type]', $entity->getEntityTypeId());
$this->assertEqualsWithJs('attributes[data-entity-uuid]', $entity->uuid());
$this->assertEqualsWithJs('attributes[data-entity-substitution]', 'canonical');
$this->assertEqualsWithJs('href_dirty_check', $entity->toUrl()->toString());
// Edit the href field and set an external url.
$href_field->setValue('http://example.com');
// Save the dialog input.
$this->click('.editor-link-dialog button:contains("Save")');
// Wait for the dialog to close.
$web_assert->assertWaitOnAjaxRequest();
$fields = [
'data-entity-type',
'data-entity-uuid',
'data-entity-substitution',
];
foreach ($fields as $attribute) {
$link_attribute = $this->getLinkAttributeFromEditor($attribute);
$this->assertNull($link_attribute, 'The link does not contain an attribute by the name of "' . $attribute . '"');
}
$href_attribute = $this->getLinkAttributeFromEditor('href');
$this->assertEquals('http://example.com', $href_attribute, 'The link href is correct.');
}
/**
* Asserts that a variable is empty.
*
* @param string $field_name
* The name of the field.
*/
private function assertEmptyWithJs($field_name) {
$javascript = "(function (){ return jQuery('input[name=\"" . $field_name . "\"]').val(); })()";
$field_value = $this->getSession()->evaluateScript($javascript);
$this->assertEmpty($field_value, 'The "' . $field_name . '" field is empty.');
}
/**
* Asserts that two variables are equal.
*
* @param string $field_name
* The name of the field.
* @param string $expected
* The expected value.
*/
private function assertEqualsWithJs($field_name, $expected) {
$javascript = "(function (){ return jQuery('input[name=\"" . $field_name . "\"]').val(); })()";
$field_value = $this->getSession()->evaluateScript($javascript);
$this->assertEquals($expected, $field_value, 'The "' . $field_name . '" field has a value of "' . $expected . '".');
}
/**
* Gets an attribute of the first link in the ckeditor editor.
*
* @param string $attribute
* The attribute name.
*
* @return string|null
* The attribute, or null if the attribute is not found on the element.
*/
private function getLinkAttributeFromEditor($attribute) {
// We can't use $session->switchToIFrame() here, because the iframe does not
// have a name.
$javascript = <<<JS
(function(){
var iframes = document.getElementsByClassName('cke_wysiwyg_frame');
if (iframes.length) {
var doc = iframes[0].contentDocument || iframes[0].contentWindow.document;
var link = doc.getElementsByTagName('a')[0];
return link.getAttribute("$attribute");
}
})()
JS;
return $this->getSession()->evaluateScript($javascript);
}
}
@@ -0,0 +1,59 @@
<?php
namespace Drupal\Tests\linkit\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
/**
* Tests the linkit alterations on the text format forms.
*
* @group linkit
*/
class LinkitFormatAdminTest extends JavascriptTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['editor', 'filter', 'linkit'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$account = $this->drupalCreateUser([
'administer filters',
]);
$this->drupalLogin($account);
}
/**
* Tests that linkit filter is toggling the filter_html allowed tags.
*/
public function testToggleLinkitFilter() {
$session = $this->getSession();
$page = $session->getPage();
// Go to add filter page.
$this->drupalGet('admin/config/content/formats/add');
$this->assertSession()->statusCodeEquals(200);
// Enable the 'Limit allowed HTML tags and correct faulty HTML' filter.
$page->findField('filters[filter_html][status]')->check();
$javascript = "(function (){ return jQuery('p.editor-update-message > strong').text(); })()";
$this->assertNotContains('<a href hreflang data-entity-substitution data-entity-type data-entity-uuid title>', $session->evaluateScript($javascript));
// Enable the 'Linkit filter' filter.
$page->findField('filters[linkit][status]')->check();
$this->assertContains('<a href hreflang data-entity-substitution data-entity-type data-entity-uuid title>', $session->evaluateScript($javascript));
// Disable the 'Linkit filter' filter.
$page->findField('filters[linkit][status]')->uncheck();
$this->assertNotContains('<a href hreflang data-entity-substitution data-entity-type data-entity-uuid title>', $session->evaluateScript($javascript));
}
}
@@ -0,0 +1,83 @@
<?php
namespace Drupal\Tests\linkit\Kernel;
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Language\LanguageInterface;
/**
* Provides helper methods for assertions.
*/
trait AssertLinkitFilterTrait {
/**
* The linkit filter.
*
* @var \Drupal\filter\Plugin\FilterInterface
*/
protected $filter;
/**
* Asserts that Linkit filter correctly processes the content.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity object to check.
* @param string $langcode
* The language code of the text to be filtered.
*/
protected function assertLinkitFilter(EntityInterface $entity, $langcode = LanguageInterface::LANGCODE_SITE_DEFAULT) {
if ($entity->getEntityTypeId() === "file") {
/** @var \Drupal\file\Entity\File $entity */
$href = file_create_url($entity->getFileUri());
}
else {
$href = $entity->toUrl()->toString();
}
$input = '<a data-entity-type="' . $entity->getEntityTypeId() . '" data-entity-uuid="' . $entity->uuid() . '">Link text</a>';
$expected = '<a data-entity-type="' . $entity->getEntityTypeId() . '" data-entity-uuid="' . $entity->uuid() . '" href="' . $href . '">Link text</a>';
$this->assertSame($expected, $this->process($input, $langcode)->getProcessedText());
}
/**
* Asserts that Linkit filter correctly processes the content titles.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity object to check.
* @param string $langcode
* The language code of the text to be filtered.
*/
protected function assertLinkitFilterWithTitle(EntityInterface $entity, $langcode = LanguageInterface::LANGCODE_SITE_DEFAULT) {
if ($entity->getEntityTypeId() === "file") {
/** @var \Drupal\file\Entity\File $entity */
$href = file_create_url($entity->getFileUri());
}
else {
$href = $entity->toUrl()->toString();
}
$input = '<a data-entity-type="' . $entity->getEntityTypeId() . '" data-entity-uuid="' . $entity->uuid() . '">Link text</a>';
$expected = '<a data-entity-type="' . $entity->getEntityTypeId() . '" data-entity-uuid="' . $entity->uuid() . '" href="' . $href . '" title="' . Html::decodeEntities($entity->label()) . '">Link text</a>';
$this->assertSame($expected, $this->process($input, $langcode)->getProcessedText());
}
/**
* Test helper method that wraps the filter process method.
*
* @param string $input
* The text string to be filtered.
* @param string $langcode
* The language code of the text to be filtered.
*
* @return \Drupal\filter\FilterProcessResult
* The filtered text, wrapped in a FilterProcessResult object, and possibly
* with associated assets, cacheability metadata and placeholders.
*
* @see \Drupal\filter\Plugin\FilterInterface::process
*/
protected function process($input, $langcode = LanguageInterface::LANGCODE_SITE_DEFAULT) {
return $this->filter->process($input, $langcode);
}
}
@@ -0,0 +1,32 @@
<?php
namespace Drupal\Tests\linkit\Kernel\Entity;
use Drupal\linkit\Tests\ProfileCreationTrait;
use Drupal\Tests\linkit\Kernel\LinkitKernelTestBase;
/**
* Tests the Profile entity.
*
* @coversDefaultClass \Drupal\linkit\Entity\Profile
*
* @group linkit
*/
class ProfileTest extends LinkitKernelTestBase {
use ProfileCreationTrait;
/**
* Test the profile description.
*
* @covers ::getDescription
* @covers ::setDescription
*/
public function testDescription() {
$profile = $this->createProfile(['description' => 'foo']);
$this->assertEquals('foo', $profile->getDescription());
$profile->setDescription('bar');
$this->assertEquals('bar', $profile->getDescription());
}
}
@@ -0,0 +1,49 @@
<?php
namespace Drupal\Tests\linkit\Kernel;
/**
* Tests the entity matcher deriver.
*
* @group linkit
*/
class EntityMatcherDeriverTest extends LinkitKernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['block', 'block_content', 'node', 'field'];
/**
* The matcher manager.
*
* @var \Drupal\linkit\MatcherManager
*/
protected $manager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['block_content']);
$this->installEntitySchema('block_content');
$this->installEntitySchema('node');
$this->installConfig(['field', 'node']);
$this->manager = $this->container->get('plugin.manager.linkit.matcher');
}
/**
* Tests the deriver.
*/
public function testDeriver() {
$definition = $this->manager->getDefinition('entity:block_content', FALSE);
$this->assertNull($definition);
$definition = $this->manager->getDefinition('entity:node', FALSE);
$this->assertNotNull($definition);
}
}
@@ -0,0 +1,259 @@
<?php
namespace Drupal\Tests\linkit\Kernel;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
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 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' => Unicode::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());
}
}
@@ -0,0 +1,243 @@
<?php
namespace Drupal\Tests\linkit\Kernel;
use Drupal\Core\Form\FormState;
use Drupal\editor\Entity\Editor;
use Drupal\editor\Form\EditorLinkDialog;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\filter\Entity\FilterFormat;
use Drupal\linkit\SubstitutionManagerInterface;
use Drupal\linkit\Tests\ProfileCreationTrait;
/**
* Tests EditorLinkDialog validation and conversion functionality.
*
* @group linkit
*/
class LinkitEditorLinkDialogTest extends LinkitKernelTestBase {
use ProfileCreationTrait;
/**
* The linkit profile.
*
* @var \Drupal\linkit\ProfileInterface
*/
protected $linkitProfile;
/**
* Editor for testing.
*
* @var \Drupal\editor\EditorInterface
*/
protected $editor;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['editor', 'ckeditor', 'entity_test'];
/**
* Sets up the test.
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('entity_test');
$this->installSchema('system', ['key_value_expire']);
// Create a profile.
$this->linkitProfile = $this->createProfile();
/** @var \Drupal\linkit\MatcherManager $matcherManager */
$matcherManager = $this->container->get('plugin.manager.linkit.matcher');
// Add the entity_test matcher to the profile.
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $matcherManager->createInstance('entity:entity_test');
$this->linkitProfile->addMatcher($plugin->getConfiguration());
$this->linkitProfile->save();
// Add a text format.
$format = FilterFormat::create([
'format' => 'filtered_html',
'name' => 'Filtered HTML',
'weight' => 0,
'filters' => [],
]);
$format->save();
// Set up editor.
$this->editor = Editor::create([
'format' => 'filtered_html',
'editor' => 'ckeditor',
]);
$this->editor->setSettings([
'plugins' => [
'drupallink' => [
'linkit_enabled' => TRUE,
'linkit_profile' => $this->linkitProfile->id(),
],
],
]);
$this->editor->save();
}
/**
* Tests adding a link.
*/
public function testAdd() {
$entity_label = $this->randomString();
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = EntityTest::create(['name' => $entity_label]);
$entity->save();
$form_object = new EditorLinkDialog();
$input = [
'editor_object' => [],
'dialogOptions' => [
'title' => 'Add Link',
'dialogClass' => 'editor-link-dialog',
'autoResize' => 'true',
],
'_drupal_ajax' => '1',
'ajax_page_state' => [
'theme' => 'bartik',
'theme_token' => 'some-token',
'libraries' => '',
],
];
$form_state = (new FormState())
->setRequestMethod('POST')
->setUserInput($input)
->addBuildInfo('args', [$this->editor]);
/** @var \Drupal\Core\Form\FormBuilderInterface $form_builder */
$form_builder = $this->container->get('form_builder');
$form_id = $form_builder->getFormId($form_object, $form_state);
$form = $form_builder->retrieveForm($form_id, $form_state);
$form_builder->prepareForm($form_id, $form, $form_state);
$form_builder->processForm($form_id, $form, $form_state);
$this->assertEquals('linkit.autocomplete', $form['attributes']['href']['#autocomplete_route_name'], 'Linkit is enabled on the linkit field.');
$this->assertEmpty($form['attributes']['href']['#default_value'], 'The linkit field is empty.');
$form_state->setValue(['attributes', 'href'], 'https://example.com/');
$form_state->setValue('href_dirty_check', '');
$form_state->setValue(['attributes', 'data-entity-type'], $this->randomString());
$form_state->setValue(['attributes', 'data-entity-uuid'], $this->randomString());
$form_state->setValue(['attributes', 'data-entity-substitution'], $this->randomString());
$form_builder->submitForm($form_object, $form_state);
$this->assertEmpty($form_state->getValue(['attributes', 'data-entity-type']));
$this->assertEmpty($form_state->getValue(['attributes', 'data-entity-uuid']));
$this->assertEmpty($form_state->getValue(['attributes', 'data-entity-substitution']));
$entity_url = $entity->toUrl('canonical', ['path_processing' => FALSE])->toString();
$form_state->setValue(['attributes', 'href'], $entity_url);
$form_state->setValue('href_dirty_check', $entity_url);
$form_state->setValue(['attributes', 'data-entity-type'], $entity->getEntityTypeId());
$form_state->setValue(['attributes', 'data-entity-uuid'], $entity->uuid());
$form_state->setValue(['attributes', 'data-entity-substitution'], SubstitutionManagerInterface::DEFAULT_SUBSTITUTION);
$form_builder->submitForm($form_object, $form_state);
$this->assertEquals($entity->getEntityTypeId(), $form_state->getValue(['attributes', 'data-entity-type']), 'Attribute "data-entity-type" exists and has the correct value.');
$this->assertEquals($entity->uuid(), $form_state->getValue(['attributes', 'data-entity-uuid']), 'Attribute "data-entity-uuid" exists and has the correct value.');
$this->assertEquals(SubstitutionManagerInterface::DEFAULT_SUBSTITUTION, $form_state->getValue(['attributes', 'data-entity-substitution']), 'Attribute "data-entity-substitution" exists and has the correct value.');
}
/**
* Tests editing a link with data attributes.
*/
public function testEditWithDataAttributes() {
$entity_label = $this->randomString();
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = EntityTest::create(['name' => $entity_label]);
$entity->save();
$entity_url = $entity->toUrl('canonical', ['path_processing' => FALSE])->toString();
$form_object = new EditorLinkDialog();
$input = [
'editor_object' => [
'href' => $entity_url,
'data-entity-type' => $entity->getEntityTypeId(),
'data-entity-uuid' => $entity->uuid(),
'data-entity-substitution' => SubstitutionManagerInterface::DEFAULT_SUBSTITUTION,
],
'dialogOptions' => [
'title' => 'Edit Link',
'dialogClass' => 'editor-link-dialog',
'autoResize' => 'true',
],
'_drupal_ajax' => '1',
'ajax_page_state' => [
'theme' => 'bartik',
'theme_token' => 'some-token',
'libraries' => '',
],
];
$form_state = (new FormState())
->setRequestMethod('POST')
->setUserInput($input)
->addBuildInfo('args', [$this->editor]);
/** @var \Drupal\Core\Form\FormBuilderInterface $form_builder */
$form_builder = $this->container->get('form_builder');
$form_id = $form_builder->getFormId($form_object, $form_state);
$form = $form_builder->retrieveForm($form_id, $form_state);
$form_builder->prepareForm($form_id, $form, $form_state);
$form_builder->processForm($form_id, $form, $form_state);
$this->assertEquals('linkit.autocomplete', $form['attributes']['href']['#autocomplete_route_name'], 'Linkit is enabled on the href field.');
$this->assertEquals($entity_url, $form['attributes']['href']['#default_value'], 'The href field has the url as default value.');
$this->assertEquals($entity->getEntityTypeId(), $form_state->getValue(['attributes', 'data-entity-type']), 'Attribute "data-entity-type" exists and has the correct value.');
$this->assertEquals($entity->uuid(), $form_state->getValue(['attributes', 'data-entity-uuid']), 'Attribute "data-entity-uuid" exists and has the correct value.');
$this->assertEquals(SubstitutionManagerInterface::DEFAULT_SUBSTITUTION, $form_state->getValue(['attributes', 'data-entity-substitution']), 'Attribute "data-entity-substitution" exists and has the correct value.');
}
/**
* Tests editing a link without data attributes.
*/
public function testEditWithoutDataAttributes() {
$form_object = new EditorLinkDialog();
$input = [
'editor_object' => [
'href' => 'http://example.com/',
],
'dialogOptions' => [
'title' => 'Edit Link',
'dialogClass' => 'editor-link-dialog',
'autoResize' => 'true',
],
'_drupal_ajax' => '1',
'ajax_page_state' => [
'theme' => 'bartik',
'theme_token' => 'some-token',
'libraries' => '',
],
];
$form_state = (new FormState())
->setRequestMethod('POST')
->setUserInput($input)
->addBuildInfo('args', [$this->editor]);
/** @var \Drupal\Core\Form\FormBuilderInterface $form_builder */
$form_builder = $this->container->get('form_builder');
$form_id = $form_builder->getFormId($form_object, $form_state);
$form = $form_builder->retrieveForm($form_id, $form_state);
$form_builder->prepareForm($form_id, $form, $form_state);
$form_builder->processForm($form_id, $form, $form_state);
$this->assertEquals('linkit.autocomplete', $form['attributes']['href']['#autocomplete_route_name'], 'Linkit is enabled on the href field.');
$this->assertEquals('http://example.com/', $form['attributes']['href']['#default_value'], 'The href field default value is the external URI.');
$this->assertEmpty($form['attributes']['data-entity-type']['#default_value']);
$this->assertEmpty($form['attributes']['data-entity-uuid']['#default_value']);
$this->assertEmpty($form['attributes']['data-entity-substitution']['#default_value']);
}
}
@@ -0,0 +1,148 @@
<?php
namespace Drupal\Tests\linkit\Kernel;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\entity_test\Entity\EntityTestMul;
use Drupal\file\Entity\File;
use Drupal\filter\FilterPluginCollection;
use Drupal\language\Entity\ConfigurableLanguage;
/**
* Tests the Linkit filter.
*
* @coversDefaultClass \Drupal\linkit\Plugin\Filter\LinkitFilter
*
* @group linkit
*/
class LinkitFilterEntityTest extends LinkitKernelTestBase {
use AssertLinkitFilterTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['filter', 'entity_test', 'path', 'language', 'file'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('entity_test');
$this->installEntitySchema('entity_test_mul');
$this->installEntitySchema('file');
// Add Swedish, Danish and Finnish.
ConfigurableLanguage::createFromLangcode('sv')->save();
ConfigurableLanguage::createFromLangcode('da')->save();
ConfigurableLanguage::createFromLangcode('fi')->save();
/** @var \Drupal\Component\Plugin\PluginManagerInterface $manager */
$manager = $this->container->get('plugin.manager.filter');
$bag = new FilterPluginCollection($manager, []);
$this->filter = $bag->get('linkit');
}
/**
* Tests the linkit filter for entities with different access.
*/
public function testFilterEntityAccess() {
// Create an entity that no one have access to.
$entity_no_access = EntityTest::create(['name' => 'forbid_access']);
$entity_no_access->save();
// Create an entity that is accessible.
$entity_with_access = EntityTest::create(['name' => $this->randomMachineName()]);
$entity_with_access->save();
// Automatically set the title.
$this->filter->setConfiguration(['settings' => ['title' => 1]]);
// Make sure the title is not included.
$input = '<a data-entity-type="' . $entity_no_access->getEntityTypeId() . '" data-entity-uuid="' . $entity_no_access->uuid() . '">Link text</a>';
$this->assertFalse(strpos($this->process($input)->getProcessedText(), 'title'), 'The link does not contain a title attribute.');
$this->assertLinkitFilterWithTitle($entity_with_access);
}
/**
* Tests the linkit filter for entities with translations.
*/
public function testFilterEntityTranslations() {
// Create an entity and add translations to that.
/** @var \Drupal\entity_test\Entity\EntityTestMul $entity */
$entity = EntityTestMul::create(['name' => $this->randomMachineName()]);
$entity->addTranslation('sv', ['name' => $this->randomMachineName(), 'langcode' => 'sv']);
$entity->addTranslation('da', ['name' => $this->randomMachineName(), 'langcode' => 'da']);
$entity->addTranslation('fi', ['name' => $this->randomMachineName(), 'langcode' => 'fi']);
$entity->save();
/** @var \Drupal\Core\Path\AliasStorageInterface $path_alias_storage */
$path_alias_storage = $this->container->get('path.alias_storage');
$url = $entity->toUrl()->toString();
// Add url aliases.
$path_alias_storage->save($url, '/' . $this->randomMachineName(), 'en');
$path_alias_storage->save($url, '/' . $this->randomMachineName(), 'sv');
$path_alias_storage->save($url, '/' . $this->randomMachineName(), 'da');
$path_alias_storage->save($url, '/' . $this->randomMachineName(), 'fi');
// Disable the automatic title attribute.
$this->filter->setConfiguration(['settings' => ['title' => 0]]);
/** @var \Drupal\Core\Language\Language $language */
foreach ($entity->getTranslationLanguages() as $language) {
$this->assertLinkitFilter($entity->getTranslation($language->getId()), $language->getId());
}
// Enable the automatic title attribute.
$this->filter->setConfiguration(['settings' => ['title' => 1]]);
/** @var \Drupal\Core\Language\Language $language */
foreach ($entity->getTranslationLanguages() as $language) {
$this->assertLinkitFilterWithTitle($entity->getTranslation($language->getId()), $language->getId());
}
}
/**
* Tests the linkit filter for file entities.
*/
public function testFilterFileEntity() {
$file = File::create([
'uid' => 1,
'filename' => 'druplicon.txt',
'uri' => 'public://druplicon.txt',
'filemime' => 'text/plain',
'status' => FILE_STATUS_PERMANENT,
]);
$file->save();
// Disable the automatic title attribute.
$this->filter->setConfiguration(['settings' => ['title' => 0]]);
$this->assertLinkitFilter($file);
// Automatically set the title.
$this->filter->setConfiguration(['settings' => ['title' => 1]]);
$this->assertLinkitFilterWithTitle($file);
}
/**
* Tests that the linkit filter do not overwrite provided title attributes.
*/
public function testTitleOverwritten() {
// Create an entity.
$entity = EntityTest::create(['name' => $this->randomMachineName()]);
$entity->save();
// Automatically set the title.
$this->filter->setConfiguration(['settings' => ['title' => 1]]);
// Make sure the title is not overwritten.
$input = '<a data-entity-type="' . $entity->getEntityTypeId() . '" data-entity-uuid="' . $entity->uuid() . '" title="Do not override">Link text</a>';
$this->assertTrue(strpos($this->process($input)->getProcessedText(), 'Do not override'), 'The filer is not overwrite the provided title attribute value.');
}
}
@@ -0,0 +1,71 @@
<?php
namespace Drupal\Tests\linkit\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
/**
* Defines an abstract test base for entity kernel tests.
*/
abstract class LinkitKernelTestBase extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'system',
'user',
'filter',
'text',
'linkit',
'linkit_test',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', 'router');
$this->installSchema('system', 'sequences');
$this->installEntitySchema('user');
$this->installConfig(['filter']);
}
/**
* Creates a user.
*
* @param array $values
* (optional) The values used to create the entity.
* @param array $permissions
* (optional) Array of permission names to assign to user.
*
* @return \Drupal\user\Entity\User
* The created user entity.
*/
protected function createUser(array $values = [], array $permissions = []) {
if ($permissions) {
// Create a new role and apply permissions to it.
$role = Role::create([
'id' => strtolower($this->randomMachineName(8)),
'label' => $this->randomMachineName(8),
]);
$role->save();
user_role_grant_permissions($role->id(), $permissions);
$values['roles'][] = $role->id();
}
$account = User::create($values + [
'name' => $this->randomMachineName(),
'status' => 1,
]);
$account->enforceIsNew();
$account->save();
return $account;
}
}
@@ -0,0 +1,58 @@
<?php
namespace Drupal\Tests\linkit\Kernel\Matchers;
use Drupal\contact\Entity\ContactForm;
use Drupal\Tests\linkit\Kernel\LinkitKernelTestBase;
/**
* Tests contact form matcher.
*
* @group linkit
*/
class ContactFormMatcherTest extends LinkitKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['contact'];
/**
* The matcher manager.
*
* @var \Drupal\linkit\MatcherManager
*/
protected $manager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Create user 1 who has special permissions.
$this->createUser();
\Drupal::currentUser()->setAccount($this->createUser([], ['access site-wide contact form', 'view test entity translations']));
$this->manager = $this->container->get('plugin.manager.linkit.matcher');
ContactForm::create([
'id' => 'lorem',
'label' => 'Lorem',
])->save();
}
/**
* Tests contact form matcher.
*/
public function testMatcherWidthDefaultConfiguration() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:contact_form', []);
$suggestions = $plugin->execute('Lorem');
$this->assertEquals(1, count($suggestions->getSuggestions()), 'Correct number of suggestions');
}
}
@@ -0,0 +1,113 @@
<?php
namespace Drupal\Tests\linkit\Kernel\Matchers;
use Drupal\file\Entity\File;
use Drupal\Tests\linkit\Kernel\LinkitKernelTestBase;
/**
* Tests file matcher.
*
* @group linkit
*/
class FileMatcherTest extends LinkitKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['file_test', 'file'];
/**
* The matcher manager.
*
* @var \Drupal\linkit\MatcherManager
*/
protected $manager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('file');
$this->installSchema('system', ['key_value_expire']);
$this->installSchema('file', ['file_usage']);
$this->manager = $this->container->get('plugin.manager.linkit.matcher');
// Linkit doesn't care about the actual resource, only the entity.
foreach (['gif', 'jpg', 'png'] as $ext) {
$file = File::create([
'uid' => 1,
'filename' => 'image-test.' . $ext,
'uri' => 'public://image-test.' . $ext,
'filemime' => 'text/plain',
'status' => FILE_STATUS_PERMANENT,
]);
$file->save();
}
// Create user 1 who has special permissions.
\Drupal::currentUser()->setAccount($this->createUser(['uid' => 1]));
}
/**
* Tests file matcher.
*/
public function testFileMatcherWithDefaultConfiguration() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:file', []);
$suggestions = $plugin->execute('image-test');
$this->assertEquals(3, count($suggestions->getSuggestions()), 'Correct number of suggestions.');
}
/**
* Tests file matcher with extension filer.
*/
public function testFileMatcherWithExtensionFiler() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:file', [
'settings' => [
'file_extensions' => 'png',
],
]);
$suggestions = $plugin->execute('image-test');
$this->assertEquals(1, count($suggestions->getSuggestions()), 'Correct number of suggestions with single file extension filter.');
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:file', [
'settings' => [
'file_extensions' => 'png jpg',
],
]);
$suggestions = $plugin->execute('image-test');
$this->assertEquals(2, count($suggestions->getSuggestions()), 'Correct number of suggestions with multiple file extension filter.');
}
/**
* Tests file matcher with tokens in the matcher metadata.
*/
public function testTermMatcherWidthMetadataTokens() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:file', [
'settings' => [
'metadata' => '[file:fid] [file:field_with_no_value]',
],
]);
$suggestionCollection = $plugin->execute('Lorem');
/** @var \Drupal\linkit\Suggestion\EntitySuggestion[] $suggestions */
$suggestions = $suggestionCollection->getSuggestions();
foreach ($suggestions as $suggestion) {
$this->assertNotContains('[file:fid]', $suggestion->getDescription(), 'Raw token "[file:fid]" is not present in the description');
$this->assertNotContains('[file:field_with_no_value]', $suggestion->getDescription(), 'Raw token "[file:field_with_no_value]" is not present in the description');
}
}
}
@@ -0,0 +1,160 @@
<?php
namespace Drupal\Tests\linkit\Kernel\Matchers;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\linkit\Kernel\LinkitKernelTestBase;
/**
* Tests node matcher.
*
* @group linkit
*/
class NodeMatcherTest extends LinkitKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['field', 'node'];
/**
* The matcher manager.
*
* @var \Drupal\linkit\MatcherManager
*/
protected $manager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('node');
$this->installConfig(['field', 'node']);
$this->manager = $this->container->get('plugin.manager.linkit.matcher');
// Set the current user to a new user, else the nodes will be created by an
// anonymous user.
\Drupal::currentUser()->setAccount($this->createUser());
$type1 = NodeType::create([
'type' => 'test1',
'name' => 'Test1',
]);
$type1->save();
$type2 = NodeType::create([
'type' => 'test2',
'name' => 'Test2',
]);
$type2->save();
// Nodes with type 1.
$node = Node::create([
'title' => 'Lorem Ipsum 1',
'type' => $type1->id(),
]);
$node->save();
$node = Node::create([
'title' => 'Lorem Ipsum 2',
'type' => $type1->id(),
]);
$node->save();
// Node with type 2.
$node = Node::create([
'title' => 'Lorem Ipsum 3',
'type' => $type2->id(),
]);
$node->save();
// Unpublished node.
$node = Node::create([
'title' => 'Lorem unpublishd',
'type' => $type1->id(),
'status' => FALSE,
]);
$node->save();
// Set the current user to someone that is not the node owner.
\Drupal::currentUser()->setAccount($this->createUser([], ['access content']));
}
/**
* Tests node matcher.
*/
public function testNodeMatcherWidthDefaultConfiguration() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:node', []);
$suggestions = $plugin->execute('Lorem');
$this->assertEquals(3, count($suggestions->getSuggestions()), 'Correct number of suggestions');
}
/**
* Tests node matcher with bundle filer.
*/
public function testNodeMatcherWidthBundleFiler() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:node', [
'settings' => [
'bundles' => [
'test1' => 'test1',
],
],
]);
$suggestions = $plugin->execute('Lorem');
$this->assertEquals(2, count($suggestions->getSuggestions()), 'Correct number of suggestions');
}
/**
* Tests node matcher with include unpublished setting activated.
*/
public function testNodeMatcherWidthIncludeUnpublished() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:node', [
'settings' => [
'include_unpublished' => TRUE,
],
]);
// Test without permissions to see unpublished nodes.
$suggestions = $plugin->execute('Lorem');
$this->assertEquals(3, count($suggestions->getSuggestions()), 'Correct number of suggestions');
// Set the current user to a user with 'bypass node access' permission.
\Drupal::currentUser()->setAccount($this->createUser([], ['bypass node access']));
// Test with permissions to see unpublished nodes.
$suggestions = $plugin->execute('Lorem');
$this->assertEquals(4, count($suggestions->getSuggestions()), 'Correct number of suggestions');
}
/**
* Tests node matcher with tokens in the matcher metadata.
*/
public function testNodeMatcherWidthMetadataTokens() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:node', [
'settings' => [
'metadata' => '[node:nid] [node:field_with_no_value]',
],
]);
$suggestionCollection = $plugin->execute('Lorem');
/** @var \Drupal\linkit\Suggestion\EntitySuggestion[] $suggestions */
$suggestions = $suggestionCollection->getSuggestions();
foreach ($suggestions as $suggestion) {
$this->assertNotContains('[node:nid]', $suggestion->getDescription(), 'Raw token "[node:nid]" is not present in the description');
$this->assertNotContains('[node:field_with_no_value]', $suggestion->getDescription(), 'Raw token "[node:field_with_no_value]" is not present in the description');
}
}
}
@@ -0,0 +1,159 @@
<?php
namespace Drupal\Tests\linkit\Kernel\Matchers;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Language\LanguageInterface;
use Drupal\taxonomy\VocabularyInterface;
use Drupal\Tests\linkit\Kernel\LinkitKernelTestBase;
/**
* Tests term matcher.
*
* @todo: Use TaxonomyTestTrait when the methods allow us to define own values.
*
* @group linkit
*/
class TermMatcherTest extends LinkitKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['taxonomy'];
/**
* The matcher manager.
*
* @var \Drupal\linkit\MatcherManager
*/
protected $manager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Create user 1 who has special permissions.
$this->createUser();
\Drupal::currentUser()->setAccount($this->createUser([], ['access content']));
$this->installEntitySchema('taxonomy_term');
$this->manager = $this->container->get('plugin.manager.linkit.matcher');
$testing_vocabulary_1 = $this->createVocabulary('testing_vocabulary_1');
$testing_vocabulary_2 = $this->createVocabulary('testing_vocabulary_2');
$this->createTerm($testing_vocabulary_1, ['name' => 'foo_bar']);
$this->createTerm($testing_vocabulary_1, ['name' => 'foo_baz']);
$this->createTerm($testing_vocabulary_1, ['name' => 'foo_foo']);
$this->createTerm($testing_vocabulary_1, ['name' => 'bar']);
$this->createTerm($testing_vocabulary_2, ['name' => 'foo_bar']);
$this->createTerm($testing_vocabulary_2, ['name' => 'foo_baz']);
}
/**
* Tests term matcher with default configuration.
*/
public function testTermMatcherWidthDefaultConfiguration() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:taxonomy_term', []);
$suggestions = $plugin->execute('foo');
$this->assertEquals(5, count($suggestions->getSuggestions()), 'Correct number of suggestions');
}
/**
* Tests term matcher with bundle filer.
*/
public function testTermMatcherWidthBundleFiler() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:taxonomy_term', [
'settings' => [
'bundles' => [
'testing_vocabulary_1' => 'testing_vocabulary_1',
],
],
]);
$suggestions = $plugin->execute('foo');
$this->assertEquals(3, count($suggestions->getSuggestions()), 'Correct number of suggestions');
}
/**
* Tests term matcher with tokens in the matcher metadata.
*/
public function testTermMatcherWidthMetadataTokens() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:taxonomy_term', [
'settings' => [
'metadata' => '[term:tid] [term:field_with_no_value]',
],
]);
$suggestionCollection = $plugin->execute('Lorem');
/** @var \Drupal\linkit\Suggestion\EntitySuggestion[] $suggestions */
$suggestions = $suggestionCollection->getSuggestions();
foreach ($suggestions as $suggestion) {
$this->assertNotContains('[term:nid]', $suggestion->getDescription(), 'Raw token "[term:nid]" is not present in the description');
$this->assertNotContains('[term:field_with_no_value]', $suggestion->getDescription(), 'Raw token "[term:field_with_no_value]" is not present in the description');
}
}
/**
* Creates and saves a vocabulary.
*
* @param string $name
* The vocabulary name.
*
* @return \Drupal\Core\Entity\EntityInterface|\Drupal\taxonomy\VocabularyInterface
* The new vocabulary object.
*/
private function createVocabulary($name) {
$vocabularyStorage = \Drupal::entityTypeManager()->getStorage('taxonomy_vocabulary');
$vocabulary = $vocabularyStorage->create([
'name' => $name,
'description' => $name,
'vid' => Unicode::strtolower($name),
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
]);
$vocabulary->save();
return $vocabulary;
}
/**
* Creates and saves a new term with in vocabulary $vid.
*
* @param \Drupal\taxonomy\VocabularyInterface $vocabulary
* The vocabulary object.
* @param array $values
* (optional) An array of values to set, keyed by property name. If the
* entity type has bundles, the bundle key has to be specified.
*
* @return \Drupal\taxonomy\Entity\Term
* The new taxonomy term object.
*/
private function createTerm(VocabularyInterface $vocabulary, array $values = []) {
$filter_formats = filter_formats();
$format = array_pop($filter_formats);
$termStorage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
$term = $termStorage->create($values + [
'name' => $this->randomMachineName(),
'description' => [
'value' => $this->randomMachineName(),
// Use the first available text format.
'format' => $format->id(),
],
'vid' => $vocabulary->id(),
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
]);
$term->save();
return $term;
}
}
@@ -0,0 +1,138 @@
<?php
namespace Drupal\Tests\linkit\Kernel\Matchers;
use Drupal\Tests\linkit\Kernel\LinkitKernelTestBase;
use Drupal\user\Entity\Role;
/**
* Tests user matcher.
*
* @group linkit
*/
class UserMatcherTest extends LinkitKernelTestBase {
/**
* The matcher manager.
*
* @var \Drupal\linkit\MatcherManager
*/
protected $manager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Create user 1 who has special permissions.
$this->createUser();
\Drupal::currentUser()->setAccount($this->createUser([], ['access user profiles']));
$this->manager = $this->container->get('plugin.manager.linkit.matcher');
$custom_role = Role::create([
'id' => 'custom_role',
'label' => 'custom_role',
]);
$custom_role->save();
$custom_role_admin = Role::create([
'id' => 'custom_role_admin',
'label' => 'custom_role_admin',
]);
$custom_role_admin->save();
$this->createUser(['name' => 'lorem']);
$this->createUser(['name' => 'foo']);
$account = $this->createUser(['name' => 'ipsumlorem']);
$account->addRole($custom_role);
$account->save();
$account = $this->createUser(['name' => 'lorem_custom_role']);
$account->addRole($custom_role);
$account->save();
$account = $this->createUser(['name' => 'lorem_custom_role_admin']);
$account->addRole($custom_role_admin);
$account->save();
$account = $this->createUser(['name' => 'blocked_lorem']);
$account->block();
$account->save();
}
/**
* Tests user matcher.
*/
public function testUserMatcherWidthDefaultConfiguration() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:user', []);
$suggestions = $plugin->execute('Lorem');
$this->assertEquals(4, count($suggestions->getSuggestions()), 'Correct number of suggestions');
}
/**
* Tests user matcher with role filer.
*/
public function testUserMatcherWidthRoleFiler() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:user', [
'settings' => [
'roles' => [
'custom_role' => 'custom_role',
],
],
]);
$suggestions = $plugin->execute('Lorem');
$this->assertEquals(2, count($suggestions->getSuggestions()), 'Correct number of suggestions');
}
/**
* Tests user matcher with include blocked setting activated.
*/
public function testUserMatcherWidthIncludeBlocked() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:user', [
'settings' => [
'include_blocked' => TRUE,
],
]);
// Test without permissions to see blocked users.
$suggestions = $plugin->execute('blocked');
$this->assertEquals(0, count($suggestions->getSuggestions()), 'Correct number of suggestions');
// Set the current user to a user with 'administer users' permission.
\Drupal::currentUser()->setAccount($this->createUser([], ['administer users']));
// Test with permissions to see blocked users.
$suggestions = $plugin->execute('blocked');
$this->assertEquals(1, count($suggestions->getSuggestions()), 'Correct number of suggestions');
}
/**
* Tests user matcher with tokens in the matcher metadata.
*/
public function testTermMatcherWidthMetadataTokens() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->manager->createInstance('entity:user', [
'settings' => [
'metadata' => '[user:uid] [term:field_with_no_value]',
],
]);
$suggestionCollection = $plugin->execute('Lorem');
/** @var \Drupal\linkit\Suggestion\EntitySuggestion[] $suggestions */
$suggestions = $suggestionCollection->getSuggestions();
foreach ($suggestions as $suggestion) {
$this->assertNotContains('[user:uid]', $suggestion->getDescription(), 'Raw token "[user:nid]" is not present in the description');
$this->assertNotContains('[user:field_with_no_value]', $suggestion->getDescription(), 'Raw token "[user:field_with_no_value]" is not present in the description');
}
}
}
@@ -0,0 +1,181 @@
<?php
namespace Drupal\Tests\linkit\Kernel;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\file\Entity\File;
use Drupal\linkit\Plugin\Linkit\Substitution\Canonical as CanonicalSubstitutionPlugin;
use Drupal\linkit\Plugin\Linkit\Substitution\File as FileSubstitutionPlugin;
use Drupal\linkit\Plugin\Linkit\Substitution\Media as MediaSubstitutionPlugin;
use Drupal\media\Entity\Media;
use Drupal\media\Entity\MediaType;
use Drupal\Core\DependencyInjection\ContainerBuilder;
/**
* Tests the substitution plugins.
*
* @group linkit
*
* @requires module media_entity
*/
class SubstitutionPluginTest extends LinkitKernelTestBase {
/**
* The substitution manager.
*
* @var \Drupal\linkit\SubstitutionManagerInterface
*/
protected $substitutionManager;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Additional modules to enable.
*
* @var array
*/
public static $modules = [
'file',
'entity_test',
'media',
'image',
'field',
];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->substitutionManager = $this->container->get('plugin.manager.linkit.substitution');
$this->entityTypeManager = $this->container->get('entity_type.manager');
$this->installEntitySchema('file');
$this->installEntitySchema('entity_test');
$this->installEntitySchema('media');
$this->installEntitySchema('media_type');
$this->installEntitySchema('field_storage_config');
$this->installEntitySchema('field_config');
$this->installSchema('file', ['file_usage']);
unset($GLOBALS['config']['system.file']);
\Drupal::configFactory()->getEditable('system.file')->set('default_scheme', 'public')->save();
}
/**
* {@inheritdoc}
*/
public function register(ContainerBuilder $container) {
parent::register($container);
$container->register('stream_wrapper.public', 'Drupal\Core\StreamWrapper\PublicStream')
->addTag('stream_wrapper', ['scheme' => 'public']);
}
/**
* {@inheritdoc}
*/
protected function setUpFilesystem() {
$public_file_directory = $this->siteDirectory . '/files';
require_once 'core/includes/file.inc';
mkdir($this->siteDirectory, 0775);
mkdir($this->siteDirectory . '/files', 0775);
mkdir($this->siteDirectory . '/files/config/' . CONFIG_SYNC_DIRECTORY, 0775, TRUE);
$this->setSetting('file_public_path', $public_file_directory);
$GLOBALS['config_directories'] = [
CONFIG_SYNC_DIRECTORY => $this->siteDirectory . '/files/config/sync',
];
}
/**
* Test the file substitution.
*/
public function testFileSubstitutions() {
$fileSubstitution = $this->substitutionManager->createInstance('file');
$file = File::create([
'uid' => 1,
'filename' => 'druplicon.txt',
'uri' => 'public://druplicon.txt',
'filemime' => 'text/plain',
'status' => FILE_STATUS_PERMANENT,
]);
$file->save();
$this->assertEquals($GLOBALS['base_url'] . '/' . $this->siteDirectory . '/files/druplicon.txt', $fileSubstitution->getUrl($file)->getGeneratedUrl());
$entity_type = $this->entityTypeManager->getDefinition('file');
$this->assertTrue(FileSubstitutionPlugin::isApplicable($entity_type), 'The entity type File is applicable the file substitution.');
$entity_type = $this->entityTypeManager->getDefinition('entity_test');
$this->assertFalse(FileSubstitutionPlugin::isApplicable($entity_type), 'The entity type EntityTest is not applicable the file substitution.');
}
/**
* Test the canonical substitution.
*/
public function testCanonicalSubstitution() {
$canonicalSubstitution = $this->substitutionManager->createInstance('canonical');
$entity = EntityTest::create([]);
$entity->save();
$this->assertEquals('/entity_test/1', $canonicalSubstitution->getUrl($entity)->getGeneratedUrl());
$entity_type = $this->entityTypeManager->getDefinition('entity_test');
$this->assertTrue(CanonicalSubstitutionPlugin::isApplicable($entity_type), 'The entity type EntityTest is applicable the canonical substitution.');
$entity_type = $this->entityTypeManager->getDefinition('file');
$this->assertFalse(CanonicalSubstitutionPlugin::isApplicable($entity_type), 'The entity type File is not applicable the canonical substitution.');
}
/**
* Test the media substitution.
*/
public function testMediaSubstitution() {
// Set up media bundle and fields.
$media_type = MediaType::create([
'label' => 'test',
'id' => 'test',
'description' => 'Test type.',
'source' => 'file',
]);
$media_type->save();
$source_field = $media_type->getSource()->createSourceField($media_type);
$source_field->getFieldStorageDefinition()->save();
$source_field->save();
$media_type->set('source_configuration', [
'source_field' => $source_field->getName(),
])->save();
$file = File::create([
'uid' => 1,
'filename' => 'druplicon.txt',
'uri' => 'public://druplicon.txt',
'filemime' => 'text/plain',
'status' => FILE_STATUS_PERMANENT,
]);
$file->save();
$media = Media::create([
'bundle' => 'test',
$source_field->getName() => ['target_id' => $file->id()],
]);
$media->save();
$media_substitution = $this->substitutionManager->createInstance('media');
$this->assertEquals($GLOBALS['base_url'] . '/' . $this->siteDirectory . '/files/druplicon.txt', $media_substitution->getUrl($media)->getGeneratedUrl());
$entity_type = $this->entityTypeManager->getDefinition('media');
$this->assertTrue(MediaSubstitutionPlugin::isApplicable($entity_type), 'The entity type Media is applicable the media substitution.');
$entity_type = $this->entityTypeManager->getDefinition('file');
$this->assertFalse(MediaSubstitutionPlugin::isApplicable($entity_type), 'The entity type File is not applicable the media substitution.');
}
}