1<?php 2 3namespace Drupal\Tests\taxonomy\Functional; 4 5use Drupal\Component\Utility\Tags; 6use Drupal\Core\Field\FieldStorageDefinitionInterface; 7use Drupal\field\Entity\FieldConfig; 8use Drupal\taxonomy\Entity\Term; 9 10/** 11 * Tests load, save and delete for taxonomy terms. 12 * 13 * @group taxonomy 14 */ 15class TermTest extends TaxonomyTestBase { 16 17 /** 18 * Vocabulary for testing. 19 * 20 * @var \Drupal\taxonomy\VocabularyInterface 21 */ 22 protected $vocabulary; 23 24 /** 25 * Taxonomy term reference field for testing. 26 * 27 * @var \Drupal\field\FieldConfigInterface 28 */ 29 protected $field; 30 31 /** 32 * Modules to enable. 33 * 34 * @var string[] 35 */ 36 protected static $modules = ['block']; 37 38 /** 39 * {@inheritdoc} 40 */ 41 protected $defaultTheme = 'classy'; 42 43 /** 44 * {@inheritdoc} 45 */ 46 protected function setUp(): void { 47 parent::setUp(); 48 49 $this->drupalPlaceBlock('local_actions_block'); 50 $this->drupalPlaceBlock('local_tasks_block'); 51 $this->drupalPlaceBlock('page_title_block'); 52 53 $this->drupalLogin($this->drupalCreateUser([ 54 'administer taxonomy', 55 'bypass node access', 56 ])); 57 $this->vocabulary = $this->createVocabulary(); 58 59 $field_name = 'taxonomy_' . $this->vocabulary->id(); 60 61 $handler_settings = [ 62 'target_bundles' => [ 63 $this->vocabulary->id() => $this->vocabulary->id(), 64 ], 65 'auto_create' => TRUE, 66 ]; 67 $this->createEntityReferenceField('node', 'article', $field_name, NULL, 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED); 68 $this->field = FieldConfig::loadByName('node', 'article', $field_name); 69 70 /** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */ 71 $display_repository = \Drupal::service('entity_display.repository'); 72 $display_repository->getFormDisplay('node', 'article') 73 ->setComponent($field_name, [ 74 'type' => 'options_select', 75 ]) 76 ->save(); 77 $display_repository->getViewDisplay('node', 'article') 78 ->setComponent($field_name, [ 79 'type' => 'entity_reference_label', 80 ]) 81 ->save(); 82 } 83 84 /** 85 * The "parent" field must restrict references to the same vocabulary. 86 */ 87 public function testParentHandlerSettings() { 88 $vocabulary_fields = \Drupal::service('entity_field.manager')->getFieldDefinitions('taxonomy_term', $this->vocabulary->id()); 89 $parent_target_bundles = $vocabulary_fields['parent']->getSetting('handler_settings')['target_bundles']; 90 $this->assertSame([$this->vocabulary->id() => $this->vocabulary->id()], $parent_target_bundles); 91 } 92 93 /** 94 * Tests terms in a single and multiple hierarchy. 95 */ 96 public function testTaxonomyTermHierarchy() { 97 // Create two taxonomy terms. 98 $term1 = $this->createTerm($this->vocabulary); 99 $term2 = $this->createTerm($this->vocabulary); 100 101 // Get the taxonomy storage. 102 /** @var \Drupal\taxonomy\TermStorageInterface $taxonomy_storage */ 103 $taxonomy_storage = $this->container->get('entity_type.manager')->getStorage('taxonomy_term'); 104 105 // Check that hierarchy is flat. 106 $this->assertEquals(0, $taxonomy_storage->getVocabularyHierarchyType($this->vocabulary->id()), 'Vocabulary is flat.'); 107 108 // Edit $term2, setting $term1 as parent. 109 $edit = []; 110 $edit['parent[]'] = [$term1->id()]; 111 $this->drupalGet('taxonomy/term/' . $term2->id() . '/edit'); 112 $this->submitForm($edit, 'Save'); 113 114 // Check the hierarchy. 115 $children = $taxonomy_storage->loadChildren($term1->id()); 116 $parents = $taxonomy_storage->loadParents($term2->id()); 117 $this->assertTrue(isset($children[$term2->id()]), 'Child found correctly.'); 118 $this->assertTrue(isset($parents[$term1->id()]), 'Parent found correctly.'); 119 120 // Load and save a term, confirming that parents are still set. 121 $term = Term::load($term2->id()); 122 $term->save(); 123 $parents = $taxonomy_storage->loadParents($term2->id()); 124 $this->assertTrue(isset($parents[$term1->id()]), 'Parent found correctly.'); 125 126 // Create a third term and save this as a parent of term2. 127 $term3 = $this->createTerm($this->vocabulary); 128 $term2->parent = [$term1->id(), $term3->id()]; 129 $term2->save(); 130 $parents = $taxonomy_storage->loadParents($term2->id()); 131 $this->assertArrayHasKey($term1->id(), $parents); 132 $this->assertArrayHasKey($term3->id(), $parents); 133 } 134 135 /** 136 * Tests that many terms with parents show on each page. 137 */ 138 public function testTaxonomyTermChildTerms() { 139 // Set limit to 10 terms per page. Set variable to 9 so 10 terms appear. 140 $this->config('taxonomy.settings')->set('terms_per_page_admin', '9')->save(); 141 $term1 = $this->createTerm($this->vocabulary); 142 $terms_array = []; 143 144 $taxonomy_storage = $this->container->get('entity_type.manager')->getStorage('taxonomy_term'); 145 146 // Create 40 terms. Terms 1-12 get parent of $term1. All others are 147 // individual terms. 148 for ($x = 1; $x <= 40; $x++) { 149 $edit = []; 150 // Set terms in order so we know which terms will be on which pages. 151 $edit['weight'] = $x; 152 153 // Set terms 1-20 to be children of first term created. 154 if ($x <= 12) { 155 $edit['parent'] = $term1->id(); 156 } 157 $term = $this->createTerm($this->vocabulary, $edit); 158 $children = $taxonomy_storage->loadChildren($term1->id()); 159 $parents = $taxonomy_storage->loadParents($term->id()); 160 $terms_array[$x] = Term::load($term->id()); 161 } 162 163 // Get Page 1. Parent term and terms 1-13 are displayed. 164 $this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview'); 165 $this->assertSession()->pageTextContains($term1->getName()); 166 for ($x = 1; $x <= 13; $x++) { 167 $this->assertSession()->pageTextContains($terms_array[$x]->getName()); 168 } 169 170 // Get Page 2. Parent term and terms 1-18 are displayed. 171 $this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview', ['query' => ['page' => 1]]); 172 $this->assertSession()->pageTextContains($term1->getName()); 173 for ($x = 1; $x <= 18; $x++) { 174 $this->assertSession()->pageTextContains($terms_array[$x]->getName()); 175 } 176 177 // Get Page 3. No parent term and no terms <18 are displayed. Terms 18-25 178 // are displayed. 179 $this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview', ['query' => ['page' => 2]]); 180 $this->assertSession()->pageTextNotContains($term1->getName()); 181 for ($x = 1; $x <= 17; $x++) { 182 $this->assertSession()->pageTextNotContains($terms_array[$x]->getName()); 183 } 184 for ($x = 18; $x <= 25; $x++) { 185 $this->assertSession()->pageTextContains($terms_array[$x]->getName()); 186 } 187 } 188 189 /** 190 * Tests that hook_node_$op implementations work correctly. 191 * 192 * Save & edit a node and assert that taxonomy terms are saved/loaded properly. 193 */ 194 public function testTaxonomyNode() { 195 // Create two taxonomy terms. 196 $term1 = $this->createTerm($this->vocabulary); 197 $term2 = $this->createTerm($this->vocabulary); 198 199 // Post an article. 200 $edit = []; 201 $edit['title[0][value]'] = $this->randomMachineName(); 202 $edit['body[0][value]'] = $this->randomMachineName(); 203 $edit[$this->field->getName() . '[]'] = $term1->id(); 204 $this->drupalGet('node/add/article'); 205 $this->submitForm($edit, 'Save'); 206 207 // Check that the term is displayed when the node is viewed. 208 $node = $this->drupalGetNodeByTitle($edit['title[0][value]']); 209 $this->drupalGet('node/' . $node->id()); 210 $this->assertSession()->pageTextContains($term1->getName()); 211 212 $this->clickLink('Edit'); 213 $this->assertSession()->pageTextContains($term1->getName()); 214 $this->submitForm([], 'Save'); 215 $this->assertSession()->pageTextContains($term1->getName()); 216 217 // Edit the node with a different term. 218 $edit[$this->field->getName() . '[]'] = $term2->id(); 219 $this->drupalGet('node/' . $node->id() . '/edit'); 220 $this->submitForm($edit, 'Save'); 221 222 $this->drupalGet('node/' . $node->id()); 223 $this->assertSession()->pageTextContains($term2->getName()); 224 225 // Preview the node. 226 $this->drupalGet('node/' . $node->id() . '/edit'); 227 $this->submitForm($edit, 'Preview'); 228 // Ensure that term is displayed when previewing the node. 229 $this->assertSession()->pageTextContainsOnce($term2->getName()); 230 $this->drupalGet('node/' . $node->id() . '/edit'); 231 $this->submitForm([], 'Preview'); 232 // Ensure that term is displayed when previewing the node again. 233 $this->assertSession()->pageTextContainsOnce($term2->getName()); 234 } 235 236 /** 237 * Tests term creation with a free-tagging vocabulary from the node form. 238 */ 239 public function testNodeTermCreationAndDeletion() { 240 // Enable tags in the vocabulary. 241 $field = $this->field; 242 \Drupal::service('entity_display.repository') 243 ->getFormDisplay($field->getTargetEntityTypeId(), $field->getTargetBundle()) 244 ->setComponent($field->getName(), [ 245 'type' => 'entity_reference_autocomplete_tags', 246 'settings' => [ 247 'placeholder' => 'Start typing here.', 248 ], 249 ]) 250 ->save(); 251 // Prefix the terms with a letter to ensure there is no clash in the first 252 // three letters. 253 // @see https://www.drupal.org/node/2397691 254 $terms = [ 255 'term1' => 'a' . $this->randomMachineName(), 256 'term2' => 'b' . $this->randomMachineName(), 257 'term3' => 'c' . $this->randomMachineName() . ', ' . $this->randomMachineName(), 258 'term4' => 'd' . $this->randomMachineName(), 259 ]; 260 261 $edit = []; 262 $edit['title[0][value]'] = $this->randomMachineName(); 263 $edit['body[0][value]'] = $this->randomMachineName(); 264 // Insert the terms in a comma separated list. Vocabulary 1 is a 265 // free-tagging field created by the default profile. 266 $edit[$field->getName() . '[target_id]'] = Tags::implode($terms); 267 268 // Verify the placeholder is there. 269 $this->drupalGet('node/add/article'); 270 $this->assertSession()->responseContains('placeholder="Start typing here."'); 271 272 // Preview and verify the terms appear but are not created. 273 $this->submitForm($edit, 'Preview'); 274 foreach ($terms as $term) { 275 $this->assertSession()->pageTextContains($term); 276 } 277 $tree = $this->container->get('entity_type.manager')->getStorage('taxonomy_term')->loadTree($this->vocabulary->id()); 278 $this->assertTrue(empty($tree), 'The terms are not created on preview.'); 279 280 // taxonomy.module does not maintain its static caches. 281 taxonomy_terms_static_reset(); 282 283 // Save, creating the terms. 284 $this->drupalGet('node/add/article'); 285 $this->submitForm($edit, 'Save'); 286 $this->assertSession()->pageTextContains('Article ' . $edit['title[0][value]'] . ' has been created.'); 287 288 // Verify that the creation message contains a link to a node. 289 $this->assertSession()->elementExists('xpath', '//div[@data-drupal-messages]//a[contains(@href, "node/")]'); 290 291 foreach ($terms as $term) { 292 $this->assertSession()->pageTextContains($term); 293 } 294 295 // Get the created terms. 296 $term_objects = []; 297 foreach ($terms as $key => $term) { 298 $term_objects[$key] = taxonomy_term_load_multiple_by_name($term); 299 $term_objects[$key] = reset($term_objects[$key]); 300 } 301 302 // Get the node. 303 $node = $this->drupalGetNodeByTitle($edit['title[0][value]']); 304 305 // Test editing the node. 306 $this->drupalGet('node/' . $node->id() . '/edit'); 307 $this->submitForm($edit, 'Save'); 308 foreach ($terms as $term) { 309 $this->assertSession()->pageTextContains($term); 310 } 311 312 // Delete term 1 from the term edit page. 313 $this->drupalGet('taxonomy/term/' . $term_objects['term1']->id() . '/edit'); 314 $this->clickLink('Delete'); 315 $this->submitForm([], 'Delete'); 316 317 // Delete term 2 from the term delete page. 318 $this->drupalGet('taxonomy/term/' . $term_objects['term2']->id() . '/delete'); 319 $this->submitForm([], 'Delete'); 320 321 // Verify that the terms appear on the node page after the two terms were 322 // deleted. 323 $term_names = [$term_objects['term3']->getName(), $term_objects['term4']->getName()]; 324 $this->drupalGet('node/' . $node->id()); 325 foreach ($term_names as $term_name) { 326 $this->assertSession()->pageTextContains($term_name); 327 } 328 $this->assertSession()->pageTextNotContains($term_objects['term1']->getName()); 329 $this->assertSession()->pageTextNotContains($term_objects['term2']->getName()); 330 } 331 332 /** 333 * Save, edit and delete a term using the user interface. 334 */ 335 public function testTermInterface() { 336 \Drupal::service('module_installer')->install(['views']); 337 $edit = [ 338 'name[0][value]' => $this->randomMachineName(12), 339 'description[0][value]' => $this->randomMachineName(100), 340 ]; 341 // Explicitly set the parents field to 'root', to ensure that 342 // TermForm::save() handles the invalid term ID correctly. 343 $edit['parent[]'] = [0]; 344 345 // Create the term to edit. 346 $this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add'); 347 $this->submitForm($edit, 'Save'); 348 349 $terms = taxonomy_term_load_multiple_by_name($edit['name[0][value]']); 350 $term = reset($terms); 351 $this->assertNotNull($term, 'Term found in database.'); 352 353 // Submitting a term takes us to the add page; we need the List page. 354 $this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview'); 355 356 $this->clickLink('Edit'); 357 358 // Verify that the randomly generated term is present. 359 $this->assertSession()->pageTextContains($edit['name[0][value]']); 360 $this->assertSession()->pageTextContains($edit['description[0][value]']); 361 362 $edit = [ 363 'name[0][value]' => $this->randomMachineName(14), 364 'description[0][value]' => $this->randomMachineName(102), 365 ]; 366 367 // Edit the term. 368 $this->drupalGet('taxonomy/term/' . $term->id() . '/edit'); 369 $this->submitForm($edit, 'Save'); 370 371 // Check that the term is still present at admin UI after edit. 372 $this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview'); 373 $this->assertSession()->pageTextContains($edit['name[0][value]']); 374 $this->assertSession()->linkExists('Edit'); 375 376 // Check the term link can be clicked through to the term page. 377 $this->clickLink($edit['name[0][value]']); 378 $this->assertSession()->statusCodeEquals(200); 379 380 // View the term and check that it is correct. 381 $this->drupalGet('taxonomy/term/' . $term->id()); 382 $this->assertSession()->pageTextContains($edit['name[0][value]']); 383 $this->assertSession()->pageTextContains($edit['description[0][value]']); 384 385 // Did this page request display a 'term-listing-heading'? 386 $this->assertSession()->elementExists('xpath', '//div[contains(@class, "field--name-description")]'); 387 // Check that it does NOT show a description when description is blank. 388 $term->setDescription(NULL); 389 $term->save(); 390 $this->drupalGet('taxonomy/term/' . $term->id()); 391 $this->assertSession()->elementNotExists('xpath', '//div[contains(@class, "field--entity-taxonomy-term--description")]'); 392 393 // Check that the description value is processed. 394 $value = $this->randomMachineName(); 395 $term->setDescription($value); 396 $term->save(); 397 $this->assertEquals("<p>{$value}</p>\n", $term->description->processed); 398 399 // Check that the term feed page is working. 400 $this->drupalGet('taxonomy/term/' . $term->id() . '/feed'); 401 402 // Delete the term. 403 $this->drupalGet('taxonomy/term/' . $term->id() . '/edit'); 404 $this->clickLink('Delete'); 405 $this->submitForm([], 'Delete'); 406 407 // Assert that the term no longer exists. 408 $this->drupalGet('taxonomy/term/' . $term->id()); 409 $this->assertSession()->statusCodeEquals(404); 410 } 411 412 /** 413 * Save, edit and delete a term using the user interface. 414 */ 415 public function testTermReorder() { 416 $assert = $this->assertSession(); 417 $this->createTerm($this->vocabulary); 418 $this->createTerm($this->vocabulary); 419 $this->createTerm($this->vocabulary); 420 421 $taxonomy_storage = $this->container->get('entity_type.manager')->getStorage('taxonomy_term'); 422 423 // Fetch the created terms in the default alphabetical order, i.e. term1 424 // precedes term2 alphabetically, and term2 precedes term3. 425 $taxonomy_storage->resetCache(); 426 list($term1, $term2, $term3) = $taxonomy_storage->loadTree($this->vocabulary->id(), 0, NULL, TRUE); 427 428 $this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview'); 429 430 // Each term has four hidden fields, "tid:1:0[tid]", "tid:1:0[parent]", 431 // "tid:1:0[depth]", and "tid:1:0[weight]". Change the order to term2, 432 // term3, term1 by setting weight property, make term3 a child of term2 by 433 // setting the parent and depth properties, and update all hidden fields. 434 $hidden_edit = [ 435 'terms[tid:' . $term2->id() . ':0][term][tid]' => $term2->id(), 436 'terms[tid:' . $term2->id() . ':0][term][parent]' => 0, 437 'terms[tid:' . $term2->id() . ':0][term][depth]' => 0, 438 'terms[tid:' . $term3->id() . ':0][term][tid]' => $term3->id(), 439 'terms[tid:' . $term3->id() . ':0][term][parent]' => $term2->id(), 440 'terms[tid:' . $term3->id() . ':0][term][depth]' => 1, 441 'terms[tid:' . $term1->id() . ':0][term][tid]' => $term1->id(), 442 'terms[tid:' . $term1->id() . ':0][term][parent]' => 0, 443 'terms[tid:' . $term1->id() . ':0][term][depth]' => 0, 444 ]; 445 // Because we can't post hidden form elements, we have to change them in 446 // code here, and then submit. 447 foreach ($hidden_edit as $field => $value) { 448 $node = $assert->hiddenFieldExists($field); 449 $node->setValue($value); 450 } 451 // Edit non-hidden elements within submitForm(). 452 $edit = [ 453 'terms[tid:' . $term2->id() . ':0][weight]' => 0, 454 'terms[tid:' . $term3->id() . ':0][weight]' => 1, 455 'terms[tid:' . $term1->id() . ':0][weight]' => 2, 456 ]; 457 $this->submitForm($edit, 'Save'); 458 459 $taxonomy_storage->resetCache(); 460 $terms = $taxonomy_storage->loadTree($this->vocabulary->id()); 461 $this->assertEquals($term2->id(), $terms[0]->tid, 'Term 2 was moved above term 1.'); 462 $this->assertEquals([$term2->id()], $terms[1]->parents, 'Term 3 was made a child of term 2.'); 463 $this->assertEquals($term1->id(), $terms[2]->tid, 'Term 1 was moved below term 2.'); 464 465 $this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview'); 466 $this->submitForm([], 'Reset to alphabetical'); 467 // Submit confirmation form. 468 $this->submitForm([], 'Reset to alphabetical'); 469 // Ensure form redirected back to overview. 470 $this->assertSession()->addressEquals('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview'); 471 472 $taxonomy_storage->resetCache(); 473 $terms = $taxonomy_storage->loadTree($this->vocabulary->id(), 0, NULL, TRUE); 474 $this->assertEquals($term1->id(), $terms[0]->id(), 'Term 1 was moved to back above term 2.'); 475 $this->assertEquals($term2->id(), $terms[1]->id(), 'Term 2 was moved to back below term 1.'); 476 $this->assertEquals($term3->id(), $terms[2]->id(), 'Term 3 is still below term 2.'); 477 $this->assertEquals([$term2->id()], $terms[2]->parents, 'Term 3 is still a child of term 2.'); 478 } 479 480 /** 481 * Tests saving a term with multiple parents through the UI. 482 */ 483 public function testTermMultipleParentsInterface() { 484 // Add a new term to the vocabulary so that we can have multiple parents. 485 $parent = $this->createTerm($this->vocabulary); 486 487 // Add a new term with multiple parents. 488 $edit = [ 489 'name[0][value]' => $this->randomMachineName(12), 490 'description[0][value]' => $this->randomMachineName(100), 491 'parent[]' => [0, $parent->id()], 492 ]; 493 // Save the new term. 494 $this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add'); 495 $this->submitForm($edit, 'Save'); 496 497 // Check that the term was successfully created. 498 $terms = taxonomy_term_load_multiple_by_name($edit['name[0][value]']); 499 $term = reset($terms); 500 $this->assertNotNull($term, 'Term found in database.'); 501 $this->assertEquals($edit['name[0][value]'], $term->getName(), 'Term name was successfully saved.'); 502 $this->assertEquals($edit['description[0][value]'], $term->getDescription(), 'Term description was successfully saved.'); 503 // Check that the parent tid is still there. The other parent (<root>) is 504 // not added by \Drupal\taxonomy\TermStorageInterface::loadParents(). 505 $parents = $this->container->get('entity_type.manager')->getStorage('taxonomy_term')->loadParents($term->id()); 506 $parent = reset($parents); 507 $this->assertEquals($edit['parent[]'][1], $parent->id(), 'Term parents were successfully saved.'); 508 } 509 510 /** 511 * Tests taxonomy_term_load_multiple_by_name(). 512 */ 513 public function testTaxonomyGetTermByName() { 514 $term = $this->createTerm($this->vocabulary); 515 516 // Load the term with the exact name. 517 $terms = taxonomy_term_load_multiple_by_name($term->getName()); 518 $this->assertTrue(isset($terms[$term->id()]), 'Term loaded using exact name.'); 519 520 // Load the term with space concatenated. 521 $terms = taxonomy_term_load_multiple_by_name(' ' . $term->getName() . ' '); 522 $this->assertTrue(isset($terms[$term->id()]), 'Term loaded with extra whitespace.'); 523 524 // Load the term with name uppercased. 525 $terms = taxonomy_term_load_multiple_by_name(strtoupper($term->getName())); 526 $this->assertTrue(isset($terms[$term->id()]), 'Term loaded with uppercased name.'); 527 528 // Load the term with name lowercased. 529 $terms = taxonomy_term_load_multiple_by_name(strtolower($term->getName())); 530 $this->assertTrue(isset($terms[$term->id()]), 'Term loaded with lowercased name.'); 531 532 // Try to load an invalid term name. 533 $terms = taxonomy_term_load_multiple_by_name('Banana'); 534 $this->assertEmpty($terms, 'No term loaded with an invalid name.'); 535 536 // Try to load the term using a substring of the name. 537 $terms = taxonomy_term_load_multiple_by_name(mb_substr($term->getName(), 2), 'No term loaded with a substring of the name.'); 538 $this->assertEmpty($terms); 539 540 // Create a new term in a different vocabulary with the same name. 541 $new_vocabulary = $this->createVocabulary(); 542 $new_term = Term::create([ 543 'name' => $term->getName(), 544 'vid' => $new_vocabulary->id(), 545 ]); 546 $new_term->save(); 547 548 // Load multiple terms with the same name. 549 $terms = taxonomy_term_load_multiple_by_name($term->getName()); 550 $this->assertCount(2, $terms, 'Two terms loaded with the same name.'); 551 552 // Load single term when restricted to one vocabulary. 553 $terms = taxonomy_term_load_multiple_by_name($term->getName(), $this->vocabulary->id()); 554 $this->assertCount(1, $terms, 'One term loaded when restricted by vocabulary.'); 555 $this->assertTrue(isset($terms[$term->id()]), 'Term loaded using exact name and vocabulary machine name.'); 556 557 // Create a new term with another name. 558 $term2 = $this->createTerm($this->vocabulary); 559 560 // Try to load a term by name that doesn't exist in this vocabulary but 561 // exists in another vocabulary. 562 $terms = taxonomy_term_load_multiple_by_name($term2->getName(), $new_vocabulary->id()); 563 $this->assertEmpty($terms, 'Invalid term name restricted by vocabulary machine name not loaded.'); 564 565 // Try to load terms filtering by a non-existing vocabulary. 566 $terms = taxonomy_term_load_multiple_by_name($term2->getName(), 'non_existing_vocabulary'); 567 $this->assertCount(0, $terms, 'No terms loaded when restricted by a non-existing vocabulary.'); 568 } 569 570 /** 571 * Tests that editing and saving a node with no changes works correctly. 572 */ 573 public function testReSavingTags() { 574 // Enable tags in the vocabulary. 575 $field = $this->field; 576 \Drupal::service('entity_display.repository') 577 ->getFormDisplay($field->getTargetEntityTypeId(), $field->getTargetBundle()) 578 ->setComponent($field->getName(), [ 579 'type' => 'entity_reference_autocomplete_tags', 580 ]) 581 ->save(); 582 583 // Create a term and a node using it. 584 $term = $this->createTerm($this->vocabulary); 585 $edit = []; 586 $edit['title[0][value]'] = $this->randomMachineName(8); 587 $edit['body[0][value]'] = $this->randomMachineName(16); 588 $edit[$this->field->getName() . '[target_id]'] = $term->getName(); 589 $this->drupalGet('node/add/article'); 590 $this->submitForm($edit, 'Save'); 591 592 // Check that the term is displayed when editing and saving the node with no 593 // changes. 594 $this->clickLink('Edit'); 595 $this->assertSession()->responseContains($term->getName()); 596 $this->submitForm([], 'Save'); 597 $this->assertSession()->responseContains($term->getName()); 598 } 599 600 /** 601 * Check the breadcrumb on edit and delete a term page. 602 */ 603 public function testTermBreadcrumbs() { 604 $edit = [ 605 'name[0][value]' => $this->randomMachineName(14), 606 'description[0][value]' => $this->randomMachineName(100), 607 'parent[]' => [0], 608 ]; 609 610 // Create the term. 611 $this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add'); 612 $this->submitForm($edit, 'Save'); 613 614 $terms = taxonomy_term_load_multiple_by_name($edit['name[0][value]']); 615 $term = reset($terms); 616 $this->assertNotNull($term, 'Term found in database.'); 617 618 // Check the breadcrumb on the term edit page. 619 $this->drupalGet('taxonomy/term/' . $term->id() . '/edit'); 620 $breadcrumbs = $this->getSession()->getPage()->findAll('css', 'nav.breadcrumb ol li a'); 621 $this->assertCount(2, $breadcrumbs, 'The breadcrumbs are present on the page.'); 622 $this->assertSame('Home', $breadcrumbs[0]->getText(), 'First breadcrumb text is Home'); 623 $this->assertSame($term->label(), $breadcrumbs[1]->getText(), 'Second breadcrumb text is term name on term edit page.'); 624 $this->assertSession()->assertEscaped($breadcrumbs[1]->getText()); 625 626 // Check the breadcrumb on the term delete page. 627 $this->drupalGet('taxonomy/term/' . $term->id() . '/delete'); 628 $breadcrumbs = $this->getSession()->getPage()->findAll('css', 'nav.breadcrumb ol li a'); 629 $this->assertCount(2, $breadcrumbs, 'The breadcrumbs are present on the page.'); 630 $this->assertSame('Home', $breadcrumbs[0]->getText(), 'First breadcrumb text is Home'); 631 $this->assertSame($term->label(), $breadcrumbs[1]->getText(), 'Second breadcrumb text is term name on term delete page.'); 632 $this->assertSession()->assertEscaped($breadcrumbs[1]->getText()); 633 } 634 635} 636