3 namespace Drupal\Tests\link\Functional;
5 use Drupal\Component\Utility\Html;
6 use Drupal\Core\Entity\Entity\EntityFormDisplay;
7 use Drupal\field\Entity\FieldConfig;
8 use Drupal\field\Entity\FieldStorageConfig;
9 use Drupal\field_ui\Tests\FieldUiTestTrait;
10 use Drupal\link\LinkItemInterface;
11 use Drupal\Tests\BrowserTestBase;
14 * Tests link field UI functionality.
18 class LinkFieldUITest extends BrowserTestBase {
27 public static $modules = ['node', 'link', 'field_ui', 'block'];
30 * A user that can edit content types.
32 * @var \Drupal\user\UserInterface
37 * A user that should see the help texts.
39 * @var \Drupal\user\Entity\User
41 protected $helpTextUser;
44 * The first content type to add fields to.
46 * @var \Drupal\node\Entity\NodeType
48 protected $firstContentType;
51 * The second content type to add fields to.
53 * @var \Drupal\node\Entity\NodeType
55 protected $secondContentType;
60 protected function setUp() {
63 $this->firstContentType = $this->drupalCreateContentType();
64 $this->secondContentType = $this->drupalCreateContentType();
65 $this->adminUser = $this->drupalCreateUser(['administer content types', 'administer node fields', 'administer node display']);
66 $this->helpTextUser = $this->drupalCreateUser(['create ' . $this->secondContentType->id() . ' content']);
67 $this->drupalPlaceBlock('system_breadcrumb_block');
71 * Tests the link field UI.
73 public function testFieldUI() {
74 foreach ($this->providerTestFieldUI() as $item) {
75 list($cardinality, $link_type, $title, $label, $field_name) = $item;
76 $this->runFieldUIItem($cardinality, $link_type, $title, $label, $field_name);
81 * Provides test data for ::testFieldUI().
83 protected function providerTestFieldUI() {
84 // There are many combinations of field settings: where the description
85 // should show: variation on internal, external, both; cardinality (where
86 // the fieldset is hidden or used); and link text shown (required or
87 // optional) or disabled. There are two descriptions: field and URL help
89 $cardinalities = [1, 2];
95 LinkItemInterface::LINK_EXTERNAL,
96 LinkItemInterface::LINK_GENERIC,
97 LinkItemInterface::LINK_INTERNAL,
100 // Test all variations of link types on all cardinalities.
101 foreach ($cardinalities as $cardinality) {
102 foreach ($link_types as $link_type) {
103 // Now, test this with both the title enabled and disabled.
104 foreach ($title_settings as $title_setting) {
105 // Test both empty and non-empty labels.
106 foreach ([TRUE, FALSE] as $label_provided) {
107 // Generate a unique machine name for the field so it can be
108 // identified in the test.
114 (int) $label_provided,
117 // Use a unique label that contains some HTML.
118 $label = '<img src="http://example.com">' . $id;
124 $label_provided ? $label : '',
134 * Tests one link field UI item.
136 * @param int $cardinality
137 * The field cardinality.
138 * @param int $link_type
139 * Determine if the link is external, internal or both.
141 * Determine if the field will display the link text field.
142 * @param string $label
144 * @param string $field_name
145 * The unique machine name for the field.
147 public function runFieldUIItem($cardinality, $link_type, $title, $label, $field_name) {
148 $this->drupalLogin($this->adminUser);
149 $type_path = 'admin/structure/types/manage/' . $this->firstContentType->id();
151 // Add a link field to the newly-created type. It defaults to allowing both
152 // internal and external links.
153 $field_label = str_replace('_', ' ', $field_name);
154 $description = 'link field description';
156 'description' => $description,
158 $this->fieldUIAddNewField($type_path, $field_name, $field_label, 'link', [], $field_edit);
160 // Load the formatter page to check that the settings summary does not
161 // generate warnings.
162 // @todo Mess with the formatter settings a bit here.
163 $this->drupalGet("$type_path/display");
164 $this->assertText(t('Link text trimmed to @limit characters', ['@limit' => 80]));
166 $storage = FieldStorageConfig::create([
167 'field_name' => $field_name,
168 'entity_type' => 'node',
170 'cardinality' => $cardinality,
174 FieldConfig::create([
175 'field_storage' => $storage,
177 'bundle' => $this->secondContentType->id(),
180 'link_type' => $link_type,
184 // Make the fields visible in the form display.
185 $form_display_id = implode('.', ['node', $this->secondContentType->id(), 'default']);
186 $form_display = EntityFormDisplay::load($form_display_id);
187 $form_display->setComponent($field_name, ['region' => 'content']);
188 $form_display->save();
190 // Log in a user that is allowed to create this content type, see if
191 // the user can see the expected help text.
192 $this->drupalLogin($this->helpTextUser);
194 $add_path = 'node/add/' . $this->secondContentType->id();
195 $this->drupalGet($add_path);
197 $expected_help_texts = [
198 LinkItemInterface::LINK_EXTERNAL => 'This must be an external URL such as <em class="placeholder">http://example.com</em>.',
199 LinkItemInterface::LINK_GENERIC => 'You can also enter an internal path such as <em class="placeholder">/node/add</em> or an external URL such as <em class="placeholder">http://example.com</em>. Enter <em class="placeholder"><front></em> to link to the front page.',
200 LinkItemInterface::LINK_INTERNAL => rtrim(\Drupal::url('<front>', [], ['absolute' => TRUE]), '/'),
203 // Check that the help texts we assume should be there, is there.
204 $this->assertFieldContainsRawText($field_name, $expected_help_texts[$link_type]);
205 if ($link_type === LinkItemInterface::LINK_INTERNAL) {
206 // Internal links have no "system" description. Test that none
207 // of the other help texts show here.
208 $this->assertNoFieldContainsRawText($field_name, $expected_help_texts[LinkItemInterface::LINK_EXTERNAL]);
209 $this->assertNoFieldContainsRawText($field_name, $expected_help_texts[LinkItemInterface::LINK_GENERIC]);
211 // Also assert that the description we made is here, no matter what the
212 // cardinality or link setting.
213 if (!empty($label)) {
214 $this->assertFieldContainsRawText($field_name, $label);
219 * Checks that given field contains the given raw text.
221 * @param string $field_name
222 * The name of the field to check.
223 * @param string $text
226 protected function assertFieldContainsRawText($field_name, $text) {
227 $this->assertTrue((bool) preg_match('/' . preg_quote($text, '/') . '/ui', $this->getFieldHtml($field_name)));
231 * Checks that given field does not contain the given raw text.
233 * @param string $field_name
234 * The name of the field to check.
235 * @param string $text
238 protected function assertNoFieldContainsRawText($field_name, $text) {
239 $this->assertFalse((bool) preg_match('/' . preg_quote($text, '/') . '/ui', $this->getFieldHtml($field_name)));
243 * Returns the raw HTML for the given field.
246 * The name of the field for which to return the HTML.
251 protected function getFieldHtml($field_name) {
252 $css_id = Html::cleanCssIdentifier('edit-' . $field_name . '-wrapper');
253 return $this->xpath('//*[@id=:id]', [':id' => $css_id])[0]->getHtml();