MenuTest.php 28.4 KB
Newer Older
1 2
<?php

3 4
/**
 * @file
5
 * Definition of Drupal\menu_ui\Tests\MenuTest.
6 7
 */

8
namespace Drupal\menu_ui\Tests;
9

10
use Drupal\Component\Serialization\Json;
11

12 13 14 15
/**
 * Defines a test class for testing menu and menu link functionality.
 */
class MenuTest extends MenuWebTestBase {
16 17 18 19 20 21

  /**
   * Modules to enable.
   *
   * @var array
   */
22
  public static $modules = array('node', 'block', 'contextual', 'help', 'path', 'test_page_test');
23

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
  /**
   * A user with administration rights.
   *
   * @var \Drupal\user\Entity\User
   */
  protected $admin_user;

  /**
   * An authenticated user.
   *
   * @var \Drupal\user\Entity\User
   */
  protected $authenticated_user;

  /**
   * A test menu.
   *
   * @var \Drupal\system\Entity\Menu
   */
43
  protected $menu;
44 45 46 47 48 49

  /**
   * An array of test menu links.
   *
   * @var array
   */
50 51
  protected $items;

52
  public static function getInfo() {
53
    return array(
54
      'name' => 'Menu link creation/deletion',
55
      'description' => 'Add a custom menu, add menu links to the custom menu and Tools menu, check their data, and delete them using the menu module UI.',
56
      'group' => 'Menu'
57 58 59 60
    );
  }

  function setUp() {
61 62
    parent::setUp();

63 64
    $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));

65
    // Create users.
66 67
    $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer blocks', 'administer menu', 'create article content'));
    $this->authenticated_user = $this->drupalCreateUser(array());
68 69 70
  }

  /**
71
   * Tests menu functionality using the admin and user interfaces.
72 73 74
   */
  function testMenu() {
    // Login the user.
75
    $this->drupalLogin($this->admin_user);
76 77
    $this->items = array();

78
    $this->menu = $this->addCustomMenu();
79 80
    $this->doMenuTests();
    $this->addInvalidMenuLink();
81
    $this->addCustomMenuCRUD();
82

83 84 85 86 87 88
    // Verify that the menu links rebuild is idempotent and leaves the same
    // number of links in the table.
    $before_count = db_query('SELECT COUNT(*) FROM {menu_links}')->fetchField();
    menu_link_rebuild_defaults();
    $after_count = db_query('SELECT COUNT(*) FROM {menu_links}')->fetchField();
    $this->assertIdentical($before_count, $after_count, 'menu_link_rebuild_defaults() does not add more links');
89 90
    // Do standard user tests.
    // Login the user.
91 92
    $this->drupalLogin($this->authenticated_user);
    $this->verifyAccess(403);
93
    foreach ($this->items as $item) {
94 95
      // Paths were set as 'node/$nid'.
      $node = node_load(substr($item['link_path'], 5));
96
      $this->verifyMenuLink($item, $node);
97 98
    }

99 100
    // Login the administrator.
    $this->drupalLogin($this->admin_user);
101

102
    // Delete menu links.
103
    foreach ($this->items as $item) {
104
      $this->deleteMenuLink($item);
105 106 107
    }

    // Delete custom menu.
108
    $this->deleteCustomMenu();
109

110 111
    // Modify and reset a standard menu link.
    $item = $this->getStandardMenuLink();
112
    $old_title = $item['link_title'];
113
    $this->modifyMenuLink($item);
114
    $item = entity_load('menu_link', $item['mlid']);
115 116 117
    // Verify that a change to the description is saved.
    $description = $this->randomName(16);
    $item['options']['attributes']['title']  = $description;
118 119 120 121
    $return_value = menu_link_save($item);
    // Save the menu link again to test the return value of the procedural save
    // helper.
    $this->assertIdentical($return_value, $item->save(), 'Return value of menu_link_save() is identical to the return value of $menu_link->save().');
122
    $saved_item = entity_load('menu_link', $item['mlid']);
123
    $this->assertEqual($description, $saved_item['options']['attributes']['title'], 'Saving an existing link updates the description (title attribute)');
124
    $this->resetMenuLink($item, $old_title);
125 126
  }

127
  /**
128
   * Adds a custom menu using CRUD functions.
129 130 131
   */
  function addCustomMenuCRUD() {
    // Add a new custom menu.
132
    $menu_name = substr(hash('sha256', $this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI);
133
    $label = $this->randomName(16);
134

135 136 137
    $menu = entity_create('menu', array(
      'id' => $menu_name,
      'label' => $label,
138
      'description' => 'Description text',
139 140
    ));
    $menu->save();
141 142

    // Assert the new menu.
143
    $this->drupalGet('admin/structure/menu/manage/' . $menu_name);
144
    $this->assertRaw($label, 'Custom menu was added.');
145 146

    // Edit the menu.
147 148 149
    $new_label = $this->randomName(16);
    $menu->set('label', $new_label);
    $menu->save();
150
    $this->drupalGet('admin/structure/menu/manage/' . $menu_name);
151
    $this->assertRaw($new_label, 'Custom menu was edited.');
152 153 154
  }

  /**
155 156 157 158
   * Creates a custom menu.
   *
   * @return \Drupal\system\Entity\Menu
   *   The custom menu that has been created.
159 160
   */
  function addCustomMenu() {
161
    // Try adding a menu using a menu_name that is too long.
162
    $this->drupalGet('admin/structure/menu/add');
163
    $menu_name = substr(hash('sha256', $this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI + 1);
164
    $label = $this->randomName(16);
165
    $edit = array(
166
      'id' => $menu_name,
167
      'description' => '',
168
      'label' =>  $label,
169
    );
170
    $this->drupalPostForm('admin/structure/menu/add', $edit, t('Save'));
171

172 173
    // Verify that using a menu_name that is too long results in a validation
    // message.
174 175 176 177 178
    $this->assertRaw(t('!name cannot be longer than %max characters but is currently %length characters long.', array(
      '!name' => t('Menu name'),
      '%max' => MENU_MAX_MENU_NAME_LENGTH_UI,
      '%length' => drupal_strlen($menu_name),
    )));
179 180

    // Change the menu_name so it no longer exceeds the maximum length.
181
    $menu_name = substr(hash('sha256', $this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI);
182
    $edit['id'] = $menu_name;
183
    $this->drupalPostForm('admin/structure/menu/add', $edit, t('Save'));
184 185

    // Verify that no validation error is given for menu_name length.
186 187 188 189 190
    $this->assertNoRaw(t('!name cannot be longer than %max characters but is currently %length characters long.', array(
      '!name' => t('Menu name'),
      '%max' => MENU_MAX_MENU_NAME_LENGTH_UI,
      '%length' => drupal_strlen($menu_name),
    )));
191
    // Verify that the confirmation message is displayed.
192
    $this->assertRaw(t('Menu %label has been added.', array('%label' => $label)));
193
    $this->drupalGet('admin/structure/menu');
194
    $this->assertText($label, 'Menu created');
195

196
    // Confirm that the custom menu block is available.
197
    $this->drupalGet('admin/structure/block/list/' . \Drupal::config('system.theme')->get('default'));
198
    $this->assertText($label);
199

200
    // Enable the block.
201
    $this->drupalPlaceBlock('system_menu_block:' . $menu_name);
202
    return menu_ui_load($menu_name);
203 204 205
  }

  /**
206
   * Deletes the locally stored custom menu.
207
   *
208 209
   * This deletes the custom menu that is stored in $this->menu and performs
   * tests on the menu delete user interface.
210
   */
211
  function deleteCustomMenu() {
212 213
    $menu_name = $this->menu->id();
    $label = $this->menu->label();
214 215

    // Delete custom menu.
216
    $this->drupalPostForm("admin/structure/menu/manage/$menu_name/delete", array(), t('Delete'));
217
    $this->assertResponse(200);
218
    $this->assertRaw(t('The custom menu %title has been deleted.', array('%title' => $label)), 'Custom menu was deleted');
219
    $this->assertFalse(menu_ui_load($menu_name), 'Custom menu was deleted');
220
    // Test if all menu links associated to the menu were removed from database.
221
    $result = entity_load_multiple_by_properties('menu_link', array('menu_name' => $menu_name));
222
    $this->assertFalse($result, 'All menu links associated to the custom menu were deleted.');
223 224

    // Make sure there's no delete button on system menus.
225
    $this->drupalGet('admin/structure/menu/manage/main');
226 227 228 229 230
    $this->assertNoRaw('edit-delete', 'The delete button was not found');

    // Try to delete the main menu.
    $this->drupalGet('admin/structure/menu/manage/main/delete');
    $this->assertText(t('You are not authorized to access this page.'));
231 232 233
  }

  /**
234
   * Tests menu functionality.
235
   */
236 237
  function doMenuTests() {
    $menu_name = $this->menu->id();
238
    // Add nodes to use as links for menu links.
239 240
    $node1 = $this->drupalCreateNode(array('type' => 'article'));
    $node2 = $this->drupalCreateNode(array('type' => 'article'));
241 242
    $node3 = $this->drupalCreateNode(array('type' => 'article'));
    $node4 = $this->drupalCreateNode(array('type' => 'article'));
243 244 245 246 247 248 249
    // Create a node with an alias.
    $node5 = $this->drupalCreateNode(array(
      'type' => 'article',
      'path' => array(
        'alias' => 'node5',
      ),
    ));
250

251
    // Add menu links.
252 253 254
    $item1 = $this->addMenuLink(0, 'node/' . $node1->id(), $menu_name);
    $item2 = $this->addMenuLink($item1['mlid'], 'node/' . $node2->id(), $menu_name, FALSE);
    $item3 = $this->addMenuLink($item2['mlid'], 'node/' . $node3->id(), $menu_name);
255 256 257 258 259 260
    $this->assertMenuLink($item1['mlid'], array(
      'depth' => 1,
      'has_children' => 1,
      'p1' => $item1['mlid'],
      'p2' => 0,
      // We assert the language code here to make sure that the language
261
      // selection element degrades gracefully without the Language module.
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
      'langcode' => 'en',
    ));
    $this->assertMenuLink($item2['mlid'], array(
      'depth' => 2, 'has_children' => 1,
      'p1' => $item1['mlid'],
      'p2' => $item2['mlid'],
      'p3' => 0,
      // See above.
      'langcode' => 'en',
    ));
    $this->assertMenuLink($item3['mlid'], array(
      'depth' => 3,
      'has_children' => 0,
      'p1' => $item1['mlid'],
      'p2' => $item2['mlid'],
      'p3' => $item3['mlid'],
      'p4' => 0,
      // See above.
      'langcode' => 'en',
    ));
282

283 284 285
    // Verify menu links.
    $this->verifyMenuLink($item1, $node1);
    $this->verifyMenuLink($item2, $node2, $item1, $node1);
286 287 288
    $this->verifyMenuLink($item3, $node3, $item2, $node2);

    // Add more menu links.
289 290
    $item4 = $this->addMenuLink(0, 'node/' . $node4->id(), $menu_name);
    $item5 = $this->addMenuLink($item4['mlid'], 'node/' . $node5->id(), $menu_name);
291 292
    // Create a menu link pointing to an alias.
    $item6 = $this->addMenuLink($item4['mlid'], 'node5', $menu_name, TRUE, '0', 'node/' . $node5->id());
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
    $this->assertMenuLink($item4['mlid'], array(
      'depth' => 1,
      'has_children' => 1,
      'p1' => $item4['mlid'],
      'p2' => 0,
      // See above.
      'langcode' => 'en',
    ));
    $this->assertMenuLink($item5['mlid'], array(
      'depth' => 2,
      'has_children' => 0,
      'p1' => $item4['mlid'],
      'p2' => $item5['mlid'],
      'p3' => 0,
      // See above.
      'langcode' => 'en',
    ));
310 311 312 313 314 315 316 317 318 319
    $this->assertMenuLink($item6['mlid'], array(
      'depth' => 2,
      'has_children' => 0,
      'p1' => $item4['mlid'],
      'p2' => $item6['mlid'],
      'p3' => 0,
      'link_path' => 'node/' . $node5->id(),
      // See above.
      'langcode' => 'en',
    ));
320

321 322 323
    // Modify menu links.
    $this->modifyMenuLink($item1);
    $this->modifyMenuLink($item2);
324

325 326 327
    // Toggle menu links.
    $this->toggleMenuLink($item1);
    $this->toggleMenuLink($item2);
328

329 330
    // Move link and verify that descendants are updated.
    $this->moveMenuLink($item2, $item5['mlid'], $menu_name);
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
    $this->assertMenuLink($item1['mlid'], array(
      'depth' => 1,
      'has_children' => 0,
      'p1' => $item1['mlid'],
      'p2' => 0,
      // See above.
      'langcode' => 'en',
    ));
    $this->assertMenuLink($item4['mlid'], array(
      'depth' => 1,
      'has_children' => 1,
      'p1' => $item4['mlid'],
      'p2' => 0,
      // See above.
      'langcode' => 'en',
    ));
    $this->assertMenuLink($item5['mlid'], array(
      'depth' => 2,
      'has_children' => 1,
      'p1' => $item4['mlid'],
      'p2' => $item5['mlid'],
      'p3' => 0,
      // See above.
      'langcode' => 'en',
    ));
    $this->assertMenuLink($item2['mlid'], array(
      'depth' => 3,
      'has_children' => 1,
      'p1' => $item4['mlid'],
      'p2' => $item5['mlid'],
      'p3' => $item2['mlid'],
      'p4' => 0,
      // See above.
      'langcode' => 'en',
    ));
    $this->assertMenuLink($item3['mlid'], array(
      'depth' => 4,
      'has_children' => 0,
      'p1' => $item4['mlid'],
      'p2' => $item5['mlid'],
      'p3' => $item2['mlid'],
      'p4' => $item3['mlid'],
      'p5' => 0,
      // See above.
      'langcode' => 'en',
    ));
377

378
    // Add 102 menu links with increasing weights, then make sure the last-added
379
    // item's weight doesn't get changed because of the old hardcoded delta=50.
380 381
    $items = array();
    for ($i = -50; $i <= 51; $i++) {
382
      $items[$i] = $this->addMenuLink(0, 'node/' . $node1->id(), $menu_name, TRUE, strval($i));
383 384 385
    }
    $this->assertMenuLink($items[51]['mlid'], array('weight' => '51'));

386 387 388 389
    // Enable a link via the overview form.
    $this->disableMenuLink($item1);
    $edit = array();

390 391 392
    // Note in the UI the 'links[mlid:x][hidden]' form element maps to enabled,
    // or NOT hidden.
    $edit['links[mlid:' . $item1['mlid'] . '][hidden]'] = TRUE;
393
    $this->drupalPostForm('admin/structure/menu/manage/' . $item1['menu_name'], $edit, t('Save'));
394 395

    // Verify in the database.
396
    $this->assertMenuLink($item1['mlid'], array('hidden' => 0));
397

398
    // Save menu links for later tests.
399 400 401 402
    $this->items[] = $item1;
    $this->items[] = $item2;
  }

403
  /**
404
   * Adds and removes a menu link with a query string and fragment.
405 406
   */
  function testMenuQueryAndFragment() {
407
    $this->drupalLogin($this->admin_user);
408 409

    // Make a path with query and fragment on.
410
    $path = 'test-page?arg1=value1&arg2=value2';
411 412 413
    $item = $this->addMenuLink(0, $path);

    $this->drupalGet('admin/structure/menu/item/' . $item['mlid'] . '/edit');
414
    $this->assertFieldByName('link_path', $path, 'Path is found with both query and fragment.');
415 416

    // Now change the path to something without query and fragment.
417
    $path = 'test-page';
418
    $this->drupalPostForm('admin/structure/menu/item/' . $item['mlid'] . '/edit', array('link_path' => $path), t('Save'));
419
    $this->drupalGet('admin/structure/menu/item/' . $item['mlid'] . '/edit');
420
    $this->assertFieldByName('link_path', $path, 'Path no longer has query or fragment.');
421 422
  }

423
  /**
424
   * Tests renaming the built-in menu.
425 426
   */
  function testSystemMenuRename() {
427
    $this->drupalLogin($this->admin_user);
428 429 430
    $edit = array(
      'label' => $this->randomName(16),
    );
431
    $this->drupalPostForm('admin/structure/menu/manage/main', $edit, t('Save'));
432 433

    // Make sure menu shows up with new name in block addition.
434
    $default_theme = \Drupal::config('system.theme')->get('default');
435
    $this->drupalget('admin/structure/block/list/' . $default_theme);
436 437 438
    $this->assertText($edit['label']);
  }

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
  /**
   * Tests that menu items pointing to unpublished nodes are editable.
   */
  function testUnpublishedNodeMenuItem() {
    $this->drupalLogin($this->drupalCreateUser(array('access administration pages', 'administer blocks', 'administer menu', 'create article content', 'bypass node access')));
    // Create an unpublished node.
    $node = $this->drupalCreateNode(array(
      'type' => 'article',
      'status' => NODE_NOT_PUBLISHED,
    ));

    $item = $this->addMenuLink(0, 'node/' . $node->id());
    $this->modifyMenuLink($item);

    // Test that a user with 'administer menu' but without 'bypass node access'
    // cannot see the menu item.
    $this->drupalLogout();
    $this->drupalLogin($this->admin_user);
    $this->drupalGet('admin/structure/menu/manage/' . $item['menu_name']);
    $this->assertNoText($item['link_title'], "Menu link pointing to unpublished node is only visible to users with 'bypass node access' permission");
  }

461 462 463 464
  /**
   * Tests the contextual links on a menu block.
   */
  public function testBlockContextualLinks() {
465
    $this->drupalLogin($this->drupalCreateUser(array('administer menu', 'access contextual links', 'administer blocks')));
466
    $this->addMenuLink();
467
    $block = $this->drupalPlaceBlock('system_menu_block:tools', array('label' => 'Tools', 'provider' => 'system'));
468
    $this->drupalGet('test-page');
469

470
    $id = 'block:block=' . $block->id() . ':|menu:menu=tools:';
471 472 473 474 475
    // @see \Drupal\contextual\Tests\ContextualDynamicContextTest:assertContextualLinkPlaceHolder()
    $this->assertRaw('<div data-contextual-id="'. $id . '"></div>', format_string('Contextual link placeholder with id @id exists.', array('@id' => $id)));

    // Get server-rendered contextual links.
    // @see \Drupal\contextual\Tests\ContextualDynamicContextTest:renderContextualLinks()
476 477
    $post = array('ids[0]' => $id);
    $response =  $this->drupalPost('contextual/render', 'application/json', $post, array('query' => array('destination' => 'test-page')));
478
    $this->assertResponse(200);
479
    $json = Json::decode($response);
480
    $this->assertIdentical($json[$id], '<ul class="contextual-links"><li class="block-configure"><a href="' . base_path() . 'admin/structure/block/manage/' . $block->id() . '">Configure block</a></li><li class="menu-ui-edit"><a href="' . base_path() . 'admin/structure/menu/manage/tools">Edit menu</a></li></ul>');
481 482
  }

483 484 485 486
  /**
   * Tests menu link bundles.
   */
  public function testMenuBundles() {
487
    $this->drupalLogin($this->admin_user);
488
    $menu = $this->addCustomMenu();
489 490
    // Clear the entity info cache to ensure the static caches are rebuilt.
    entity_info_cache_clear();
491
    $bundles = entity_get_bundles('menu_link');
492
    $this->assertTrue(isset($bundles[$menu->id()]));
493 494 495 496 497 498 499
    $menus = menu_list_system_menus();
    $menus[$menu->id()] = $menu->label();
    ksort($menus);
    $this->assertIdentical(array_keys($bundles), array_keys($menus));

    // Test if moving a menu link between menus changes the bundle.
    $node = $this->drupalCreateNode(array('type' => 'article'));
500
    $item = $this->addMenuLink(0, 'node/' . $node->id(), 'tools');
501 502 503 504 505 506
    $this->moveMenuLink($item, 0, $menu->id());
    $this->assertEqual($item->bundle(), 'tools', 'Menu link bundle matches the menu');

    $moved_item = entity_load('menu_link', $item->id(), TRUE);
    $this->assertNotEqual($moved_item->bundle(), $item->bundle(), 'Menu link bundle was changed');
    $this->assertEqual($moved_item->bundle(), $menu->id(), 'Menu link bundle matches the menu');
507 508 509 510

    $unsaved_item = entity_create('menu_link', array('menu_name' => $menu->id(), 'link_title' => $this->randomName(16), 'link_path' => '<front>'));
    $this->assertEqual($unsaved_item->bundle(), $menu->id(), 'Unsaved menu link bundle matches the menu');
    $this->assertEqual($unsaved_item->menu_name, $menu->id(), 'Unsaved menu link menu name matches the menu');
511 512
  }

513
  /**
514
   * Adds a menu link using the menu module UI.
515
   *
516 517 518 519 520 521 522 523 524 525 526 527
   * @param integer $plid
   *   Optional parent menu link id.
   * @param string $link
   *   Link path. Defaults to the front page.
   * @param string $menu_name
   *   Menu name. Defaults to 'tools'.
   * @param bool $expanded
   *   Whether or not this menu link is expanded. Setting this to TRUE should
   *   test whether it works when we do the authenticated_user tests. Defaults
   *   to FALSE.
   * @param string $weight
   *  Menu weight. Defaults to 0.
528 529
   * @param string $actual_link
   *   Actual link path in case $link is an alias.
530
   *
531
   * @return \Drupal\menu_link\Entity\MenuLink
532
   *   A menu link entity.
533
   */
534
  function addMenuLink($plid = 0, $link = '<front>', $menu_name = 'tools', $expanded = TRUE, $weight = '0', $actual_link = FALSE) {
535
    // View add menu link page.
536
    $this->drupalGet("admin/structure/menu/manage/$menu_name/add");
537 538
    $this->assertResponse(200);

539
    $title = '!link_' . $this->randomName(16);
540
    $edit = array(
541 542 543
      'link_path' => $link,
      'link_title' => $title,
      'description' => '',
544 545
      'enabled' => TRUE,
      'expanded' => $expanded,
546
      'parent' =>  $menu_name . ':' . $plid,
547
      'weight' => $weight,
548 549
    );

550 551 552
    if (!$actual_link) {
      $actual_link = $link;
    }
553
    // Add menu link.
554
    $this->drupalPostForm(NULL, $edit, t('Save'));
555
    $this->assertResponse(200);
556
    $this->assertText('The menu link has been saved.');
557

558 559
    $menu_links = entity_load_multiple_by_properties('menu_link', array('link_title' => $title));
    $menu_link = reset($menu_links);
560
    $this->assertTrue($menu_link, 'Menu link was found in database.');
561
    $this->assertMenuLink($menu_link->id(), array('menu_name' => $menu_name, 'link_path' => $actual_link, 'has_children' => 0, 'plid' => $plid));
562

563
    return $menu_link;
564 565 566
  }

  /**
567
   * Attempts to add menu link with invalid path or no access permission.
568
   */
569
  function addInvalidMenuLink() {
570
    foreach (array('-&-', 'admin/people/permissions', '#') as $link_path) {
571
      $edit = array(
572 573
        'link_path' => $link_path,
        'link_title' => 'title',
574
      );
575
      $this->drupalPostForm("admin/structure/menu/manage/{$this->menu->id()}/add", $edit, t('Save'));
576
      $this->assertRaw(t("The path '@path' is either invalid or you do not have access to it.", array('@path' => $link_path)), 'Menu link was not created');
577 578 579 580
    }
  }

  /**
581
   * Verifies a menu link using the menu module UI.
582
   *
583 584 585 586 587 588 589 590
   * @param array $item
   *   Menu link.
   * @param object $item_node
   *   Menu link content node.
   * @param array $parent
   *   Parent menu link.
   * @param object $parent_node
   *   Parent menu link content node.
591
   */
592
  function verifyMenuLink($item, $item_node, $parent = NULL, $parent_node = NULL) {
593 594 595 596
    // View home page.
    $this->drupalGet('');
    $this->assertResponse(200);

597
    // Verify parent menu link.
598
    if (isset($parent)) {
599
      // Verify menu link.
600
      $title = $parent['link_title'];
601
      $this->assertLink($title, 0, 'Parent menu link was displayed');
602

603
      // Verify menu link link.
604
      $this->clickLink($title);
605
      $title = $parent_node->label();
606
      $this->assertTitle(t("@title | Drupal", array('@title' => $title)), 'Parent menu link link target was correct');
607 608
    }

609
    // Verify menu link.
610
    $title = $item['link_title'];
611
    $this->assertLink($title, 0, 'Menu link was displayed');
612

613
    // Verify menu link link.
614
    $this->clickLink($title);
615
    $title = $item_node->label();
616
    $this->assertTitle(t("@title | Drupal", array('@title' => $title)), 'Menu link link target was correct');
617 618
  }

619
  /**
620 621 622 623 624 625 626 627
   * Changes the parent of a menu link using the menu module UI.
   *
   * @param array $item
   *   The menu link item to move.
   * @param int $plid
   *   The id of the new parent.
   * @param string $menu_name
   *   The menu the menu link will be moved to.
628 629 630 631 632 633 634
   */
  function moveMenuLink($item, $plid, $menu_name) {
    $mlid = $item['mlid'];

    $edit = array(
      'parent' => $menu_name . ':' . $plid,
    );
635
    $this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
636 637 638
    $this->assertResponse(200);
  }

639
  /**
640
   * Modifies a menu link using the menu module UI.
641
   *
642 643
   * @param array $item
   *   Menu link passed by reference.
644
   */
645
  function modifyMenuLink(&$item) {
646 647 648 649 650
    $item['link_title'] = $this->randomName(16);

    $mlid = $item['mlid'];
    $title = $item['link_title'];

651
    // Edit menu link.
652
    $edit = array();
653
    $edit['link_title'] = $title;
654
    $this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
655
    $this->assertResponse(200);
656
    $this->assertText('The menu link has been saved.');
657
    // Verify menu link.
658
    $this->drupalGet('admin/structure/menu/manage/' . $item['menu_name']);
659
    $this->assertText($title, 'Menu link was edited');
660 661 662
  }

  /**
663
   * Resets a standard menu link using the menu module UI.
664
   *
665 666 667 668
   * @param array $item
   *   Menu link.
   * @param string $old_title
   *   Original title for menu link.
669
   */
670
  function resetMenuLink($item, $old_title) {
671 672 673
    $mlid = $item['mlid'];
    $title = $item['link_title'];

674
    // Reset menu link.
675
    $this->drupalPostForm("admin/structure/menu/item/$mlid/reset", array(), t('Reset'));
676
    $this->assertResponse(200);
677
    $this->assertRaw(t('The menu link was reset to its default settings.'), 'Menu link was reset');
678

679
    // Verify menu link.
680
    $this->drupalGet('');
681 682
    $this->assertNoText($title, 'Menu link was reset');
    $this->assertText($old_title, 'Menu link was reset');
683 684 685
  }

  /**
686
   * Deletes a menu link using the menu module UI.
687
   *
688 689
   * @param array $item
   *   Menu link.
690
   */
691
  function deleteMenuLink($item) {
692 693 694
    $mlid = $item['mlid'];
    $title = $item['link_title'];

695
    // Delete menu link.
696
    $this->drupalPostForm("admin/structure/menu/item/$mlid/delete", array(), t('Confirm'));
697
    $this->assertResponse(200);
698
    $this->assertRaw(t('The menu link %title has been deleted.', array('%title' => $title)), 'Menu link was deleted');
699 700 701

    // Verify deletion.
    $this->drupalGet('');
702
    $this->assertNoText($title, 'Menu link was deleted');
703 704 705
  }

  /**
706
   * Alternately disables and enables a menu link.
707
   *
708 709
   * @param $item
   *   Menu link.
710
   */
711
  function toggleMenuLink($item) {
712
    $this->disableMenuLink($item);
713

714 715 716 717 718 719 720 721 722 723 724
    // Verify menu link is absent.
    $this->drupalGet('');
    $this->assertNoText($item['link_title'], 'Menu link was not displayed');
    $this->enableMenuLink($item);

    // Verify menu link is displayed.
    $this->drupalGet('');
    $this->assertText($item['link_title'], 'Menu link was displayed');
  }

  /**
725
   * Disables a menu link.
726 727 728 729 730 731
   *
   * @param $item
   *   Menu link.
   */
  function disableMenuLink($item) {
    $mlid = $item['mlid'];
732
    $edit['enabled'] = FALSE;
733
    $this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
734

735 736
    // Unlike most other modules, there is no confirmation message displayed.
    // Verify in the database.
737
    $this->assertMenuLink($mlid, array('hidden' => 1));
738
  }
739

740
  /**
741
   * Enables a menu link.
742 743 744 745 746 747
   *
   * @param $item
   *   Menu link.
   */
  function enableMenuLink($item) {
    $mlid = $item['mlid'];
748
    $edit['enabled'] = TRUE;
749
    $this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
750

751
    // Verify in the database.
752 753 754
    $this->assertMenuLink($mlid, array('hidden' => 0));
  }

755
  /**
756 757
   * Tests if administrative users other than user 1 can access the menu parents
   * AJAX callback.
758 759 760 761 762 763 764 765 766 767
   */
  public function testMenuParentsJsAccess() {
    $admin = $this->drupalCreateUser(array('administer menu'));
    $this->drupalLogin($admin);
    // Just check access to the callback overall, the POST data is irrelevant.
    $this->drupalGetAJAX('admin/structure/menu/parents');
    $this->assertResponse(200);

    // Do standard user tests.
    // Login the user.
768
    $this->drupalLogin($this->authenticated_user);
769 770 771 772
    $this->drupalGetAJAX('admin/structure/menu/parents');
    $this->assertResponse(403);
  }

773
  /**
774 775 776 777
   * Returns standard menu link.
   *
   * @return \Drupal\menu_link\Entity\MenuLink
   *   A menu link entity.
778
   */
779
  private function getStandardMenuLink() {
780 781 782
    $mlid = 0;
    // Retrieve menu link id of the Log out menu link, which will always be on
    // the front page.
783
    $query = \Drupal::entityQuery('menu_link')
784 785
      ->condition('module', 'user')
      ->condition('machine_name', 'user.logout');
786 787 788 789 790
    $result = $query->execute();
    if (!empty($result)) {
      $mlid = reset($result);
    }

791
    $this->assertTrue($mlid > 0, 'Standard menu link id was found');
792
    // Load menu link.
793
    // Use api function so that link is translated for rendering.
794
    $item = entity_load('menu_link', $mlid);
795
    $this->assertTrue((bool) $item, 'Standard menu link was loaded');
796 797 798 799
    return $item;
  }

  /**
800
   * Verifies the logged in user has the desired access to various menu pages.
801
   *
802 803
   * @param integer $response
   *   The expected HTTP response code. Defaults to 200.
804
   */
805 806
  private function verifyAccess($response = 200) {
    // View menu help page.
807 808 809
    $this->drupalGet('admin/help/menu');
    $this->assertResponse($response);
    if ($response == 200) {
810
      $this->assertText(t('Menu'), 'Menu help was displayed');
811 812
    }

813
    // View menu build overview page.
814
    $this->drupalGet('admin/structure/menu');
815 816
    $this->assertResponse($response);
    if ($response == 200) {
817
      $this->assertText(t('Menus'), 'Menu build overview page was displayed');
818 819
    }

820 821
    // View tools menu customization page.
    $this->drupalGet('admin/structure/menu/manage/' . $this->menu->id());
822
        $this->assertResponse($response);
823
    if ($response == 200) {
824
      $this->assertText(t('Tools'), 'Tools menu page was displayed');
825 826
    }

827
    // View menu edit page.
828
    $item = $this->getStandardMenuLink();
829
    $this->drupalGet('admin/structure/menu/item/' . $item['mlid'] . '/edit');
830 831
    $this->assertResponse($response);
    if ($response == 200) {
832
      $this->assertText(t('Edit menu item'), 'Menu edit page was displayed');
833 834
    }

835
    // View menu settings page.
836
    $this->drupalGet('admin/structure/menu/settings');
837 838
    $this->assertResponse($response);
    if ($response == 200) {
839
      $this->assertText(t('Menus'), 'Menu settings page was displayed');
840 841
    }

842
    // View add menu page.
843
    $this->drupalGet('admin/structure/menu/add');
844 845
    $this->assertResponse($response);
    if ($response == 200) {
846
      $this->assertText(t('Menus'), 'Add menu page was displayed');
847 848
    }
  }
849

850
}