Initial Drupal 11 with DDEV setup
This commit is contained in:
		@ -0,0 +1,4 @@
 | 
			
		||||
name: 'Tests menu link access'
 | 
			
		||||
type: module
 | 
			
		||||
package: Testing
 | 
			
		||||
version: VERSION
 | 
			
		||||
@ -0,0 +1,38 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\menu_link_access_test\Hook;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Access\AccessResult;
 | 
			
		||||
use Drupal\Core\Access\AccessResultInterface;
 | 
			
		||||
use Drupal\Core\Session\AccountInterface;
 | 
			
		||||
use Drupal\Core\Entity\EntityInterface;
 | 
			
		||||
use Drupal\Core\Hook\Attribute\Hook;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Hook implementations for menu_link_access_test.
 | 
			
		||||
 */
 | 
			
		||||
class MenuLinkAccessTestHooks {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements hook_ENTITY_TYPE_access().
 | 
			
		||||
   */
 | 
			
		||||
  #[Hook('menu_link_content_access')]
 | 
			
		||||
  public function entityTestAccess(EntityInterface $entity, $operation, AccountInterface $account): AccessResultInterface {
 | 
			
		||||
    if (in_array($operation, ['update', 'delete'])) {
 | 
			
		||||
      return AccessResult::forbidden();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return AccessResult::neutral();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements hook_ENTITY_TYPE_create_access().
 | 
			
		||||
   */
 | 
			
		||||
  #[Hook('menu_link_content_create_access')]
 | 
			
		||||
  public function entityTestCreateAccess(AccountInterface $account, $context, $entity_bundle): AccessResultInterface {
 | 
			
		||||
    return AccessResult::forbidden();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,4 @@
 | 
			
		||||
name: 'Tests MenuLinkAdd class'
 | 
			
		||||
type: module
 | 
			
		||||
package: Testing
 | 
			
		||||
version: VERSION
 | 
			
		||||
@ -0,0 +1,6 @@
 | 
			
		||||
entity.menu.add_link_form_deprecated:
 | 
			
		||||
  route_name: entity.menu.add_link_form
 | 
			
		||||
  title: 'Add link (deprecated)'
 | 
			
		||||
  class: \Drupal\menu_ui\Plugin\Menu\LocalAction\MenuLinkAdd
 | 
			
		||||
  appears_on:
 | 
			
		||||
    - entity.menu.edit_form
 | 
			
		||||
@ -0,0 +1,14 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Functional;
 | 
			
		||||
 | 
			
		||||
use Drupal\Tests\system\Functional\Module\GenericModuleTestBase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Generic module test for menu_ui.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class GenericTest extends GenericModuleTestBase {}
 | 
			
		||||
@ -0,0 +1,116 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Functional;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Url;
 | 
			
		||||
use Drupal\menu_link_content\Entity\MenuLinkContent;
 | 
			
		||||
use Drupal\Tests\system\Functional\Cache\PageCacheTagsTestBase;
 | 
			
		||||
use Drupal\system\Entity\Menu;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests the Menu and Menu Link entities' cache tags.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MenuCacheTagsTest extends PageCacheTagsTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['menu_ui', 'block', 'test_page_test'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests cache tags presence and invalidation of the Menu entity.
 | 
			
		||||
   *
 | 
			
		||||
   * Tests the following cache tags:
 | 
			
		||||
   * - "menu:<menu ID>"
 | 
			
		||||
   */
 | 
			
		||||
  public function testMenuBlock(): void {
 | 
			
		||||
    $url = Url::fromRoute('test_page_test.test_page');
 | 
			
		||||
 | 
			
		||||
    // Create a Llama menu, add a link to it and place the corresponding block.
 | 
			
		||||
    $menu = Menu::create([
 | 
			
		||||
      'id' => 'llama',
 | 
			
		||||
      'label' => 'Llama',
 | 
			
		||||
      'description' => 'Description text',
 | 
			
		||||
    ]);
 | 
			
		||||
    $menu->save();
 | 
			
		||||
    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
 | 
			
		||||
    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
 | 
			
		||||
    // Move a link into the new menu.
 | 
			
		||||
    $menu_link = $menu_link_manager->updateDefinition('test_page_test.test_page', ['menu_name' => 'llama', 'parent' => '']);
 | 
			
		||||
    $block = $this->drupalPlaceBlock('system_menu_block:llama', ['label' => 'Llama', 'provider' => 'system', 'region' => 'footer']);
 | 
			
		||||
 | 
			
		||||
    // Prime the page cache.
 | 
			
		||||
    $this->verifyPageCache($url, 'MISS');
 | 
			
		||||
 | 
			
		||||
    // Verify a cache hit, but also the presence of the correct cache tags.
 | 
			
		||||
    $expected_tags = [
 | 
			
		||||
      'http_response',
 | 
			
		||||
      'rendered',
 | 
			
		||||
      'block_view',
 | 
			
		||||
      'config:block_list',
 | 
			
		||||
      'config:block.block.' . $block->id(),
 | 
			
		||||
      'config:system.menu.llama',
 | 
			
		||||
      // The cache contexts associated with the (in)accessible menu links are
 | 
			
		||||
      // bubbled.
 | 
			
		||||
      'config:user.role.anonymous',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->verifyPageCache($url, 'HIT', $expected_tags);
 | 
			
		||||
 | 
			
		||||
    // Verify that after modifying the menu, there is a cache miss.
 | 
			
		||||
    $menu->set('label', 'Awesome llama');
 | 
			
		||||
    $menu->save();
 | 
			
		||||
    $this->verifyPageCache($url, 'MISS');
 | 
			
		||||
 | 
			
		||||
    // Verify a cache hit.
 | 
			
		||||
    $this->verifyPageCache($url, 'HIT');
 | 
			
		||||
 | 
			
		||||
    // Verify that after modifying the menu link weight, there is a cache miss.
 | 
			
		||||
    $menu_link_manager->updateDefinition('test_page_test.test_page', ['weight' => -10]);
 | 
			
		||||
    $this->verifyPageCache($url, 'MISS');
 | 
			
		||||
 | 
			
		||||
    // Verify a cache hit.
 | 
			
		||||
    $this->verifyPageCache($url, 'HIT');
 | 
			
		||||
 | 
			
		||||
    // Verify that after adding a menu link, there is a cache miss.
 | 
			
		||||
    $menu_link_2 = MenuLinkContent::create([
 | 
			
		||||
      'id' => '',
 | 
			
		||||
      'parent' => '',
 | 
			
		||||
      'title' => 'Alpaca',
 | 
			
		||||
      'menu_name' => 'llama',
 | 
			
		||||
      'link' => [
 | 
			
		||||
        ['uri' => 'internal:/'],
 | 
			
		||||
      ],
 | 
			
		||||
      'bundle' => 'menu_name',
 | 
			
		||||
    ]);
 | 
			
		||||
    $menu_link_2->save();
 | 
			
		||||
    $this->verifyPageCache($url, 'MISS');
 | 
			
		||||
 | 
			
		||||
    // Verify a cache hit.
 | 
			
		||||
    $this->verifyPageCache($url, 'HIT');
 | 
			
		||||
 | 
			
		||||
    // Verify that after resetting the first menu link, there is a cache miss.
 | 
			
		||||
    $this->assertTrue($menu_link->isResettable(), 'First link can be reset');
 | 
			
		||||
    $menu_link = $menu_link_manager->resetLink($menu_link->getPluginId());
 | 
			
		||||
    $this->verifyPageCache($url, 'MISS');
 | 
			
		||||
 | 
			
		||||
    // Verify a cache hit.
 | 
			
		||||
    $this->verifyPageCache($url, 'HIT', $expected_tags);
 | 
			
		||||
 | 
			
		||||
    // Verify that after deleting the menu, there is a cache miss.
 | 
			
		||||
    $menu->delete();
 | 
			
		||||
    $this->verifyPageCache($url, 'MISS');
 | 
			
		||||
 | 
			
		||||
    // Verify a cache hit.
 | 
			
		||||
    $this->verifyPageCache($url, 'HIT', ['config:block_list', 'config:user.role.anonymous', 'http_response', 'rendered']);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,74 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Functional;
 | 
			
		||||
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Reorder menu items.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MenuLinkReorderTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * An administrator user.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\user\UserInterface
 | 
			
		||||
   */
 | 
			
		||||
  protected $administrator;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['menu_ui', 'test_page_test', 'node', 'block'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests creating, editing, deleting menu links via node form widget.
 | 
			
		||||
   */
 | 
			
		||||
  public function testDefaultMenuLinkReorder(): void {
 | 
			
		||||
 | 
			
		||||
    // Add the main menu block.
 | 
			
		||||
    $this->drupalPlaceBlock('system_menu_block:main');
 | 
			
		||||
 | 
			
		||||
    // Assert that the Home link is available.
 | 
			
		||||
    $this->drupalGet('test-page');
 | 
			
		||||
    $this->assertSession()->linkExists('Home');
 | 
			
		||||
 | 
			
		||||
    // The administrator user that can re-order menu links.
 | 
			
		||||
    $this->administrator = $this->drupalCreateUser([
 | 
			
		||||
      'administer site configuration',
 | 
			
		||||
      'access administration pages',
 | 
			
		||||
      'administer menu',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->drupalLogin($this->administrator);
 | 
			
		||||
 | 
			
		||||
    // Change the weight of the link to a non default value.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'links[menu_plugin_id:test_page_test.front_page][weight]' => -10,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('admin/structure/menu/manage/main');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
 | 
			
		||||
    // The link is still there.
 | 
			
		||||
    $this->drupalGet('test-page');
 | 
			
		||||
    $this->assertSession()->linkExists('Home');
 | 
			
		||||
 | 
			
		||||
    // Clear all caches.
 | 
			
		||||
    $this->drupalGet('admin/config/development/performance');
 | 
			
		||||
    $this->submitForm([], 'Clear all caches');
 | 
			
		||||
 | 
			
		||||
    // Clearing all caches should not affect the state of the menu link.
 | 
			
		||||
    $this->drupalGet('test-page');
 | 
			
		||||
    $this->assertSession()->linkExists('Home');
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,247 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Functional;
 | 
			
		||||
 | 
			
		||||
use Drupal\menu_link_content\Entity\MenuLinkContent;
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests Menu UI and Content Moderation integration.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MenuUiContentModerationTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  use ContentModerationTestTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = [
 | 
			
		||||
    'block',
 | 
			
		||||
    'content_moderation',
 | 
			
		||||
    'node',
 | 
			
		||||
    'menu_ui',
 | 
			
		||||
    'test_page_test',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
 | 
			
		||||
    $this->drupalPlaceBlock('system_menu_block:main');
 | 
			
		||||
 | 
			
		||||
    // Create a 'page' content type.
 | 
			
		||||
    $this->drupalCreateContentType([
 | 
			
		||||
      'type' => 'page',
 | 
			
		||||
      'name' => 'Basic page',
 | 
			
		||||
      'display_submitted' => FALSE,
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    $workflow = $this->createEditorialWorkflow();
 | 
			
		||||
    $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page');
 | 
			
		||||
    $workflow->save();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests that node drafts can not modify the menu settings.
 | 
			
		||||
   */
 | 
			
		||||
  public function testMenuUiWithPendingRevisions(): void {
 | 
			
		||||
    $editor = $this->drupalCreateUser([
 | 
			
		||||
      'administer nodes',
 | 
			
		||||
      'administer menu',
 | 
			
		||||
      'create page content',
 | 
			
		||||
      'edit any page content',
 | 
			
		||||
      'use editorial transition create_new_draft',
 | 
			
		||||
      'use editorial transition publish',
 | 
			
		||||
      'view latest version',
 | 
			
		||||
      'view any unpublished content',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->drupalLogin($editor);
 | 
			
		||||
 | 
			
		||||
    // Create a node.
 | 
			
		||||
    $node = $this->drupalCreateNode();
 | 
			
		||||
 | 
			
		||||
    // Publish the node with no changes.
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm([], 'Save');
 | 
			
		||||
    $this->assertSession()->pageTextContains("Page {$node->label()} has been updated.");
 | 
			
		||||
 | 
			
		||||
    // Create a pending revision with no changes.
 | 
			
		||||
    $edit = ['moderation_state[0][state]' => 'draft'];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertSession()->pageTextContains("Page {$node->label()} has been updated.");
 | 
			
		||||
 | 
			
		||||
    // Add a menu link and save a new default (published) revision.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu[enabled]' => 1,
 | 
			
		||||
      'menu[title]' => 'Test menu link',
 | 
			
		||||
      'moderation_state[0][state]' => 'published',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
 | 
			
		||||
    $this->assertSession()->linkExists('Test menu link');
 | 
			
		||||
 | 
			
		||||
    // Try to change the menu link weight and save a new non-default (draft)
 | 
			
		||||
    // revision.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu[weight]' => 1,
 | 
			
		||||
      'moderation_state[0][state]' => 'draft',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
 | 
			
		||||
    // Check that the menu settings were not applied.
 | 
			
		||||
    $this->assertSession()->pageTextContains('You can only change the menu link weight for the published version of this content.');
 | 
			
		||||
 | 
			
		||||
    // Try to change the menu link parent and save a new non-default (draft)
 | 
			
		||||
    // revision.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu[menu_parent]' => 'main:test_page_test.front_page',
 | 
			
		||||
      'moderation_state[0][state]' => 'draft',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
 | 
			
		||||
    // Check that the menu settings were not applied.
 | 
			
		||||
    $this->assertSession()->pageTextContains('You can only change the parent menu link for the published version of this content.');
 | 
			
		||||
 | 
			
		||||
    // Try to delete the menu link and save a new non-default (draft) revision.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu[enabled]' => 0,
 | 
			
		||||
      'moderation_state[0][state]' => 'draft',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
 | 
			
		||||
    // Check that the menu settings were not applied.
 | 
			
		||||
    $this->assertSession()->pageTextContains('You can only remove the menu link in the published version of this content.');
 | 
			
		||||
    $this->assertSession()->linkExists('Test menu link');
 | 
			
		||||
 | 
			
		||||
    // Try to change the menu link title and description and save a new
 | 
			
		||||
    // non-default (draft) revision.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu[title]' => 'Test menu link draft',
 | 
			
		||||
      'menu[description]' => 'Test menu link description',
 | 
			
		||||
      'moderation_state[0][state]' => 'draft',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertSession()->pageTextContains("Page {$node->label()} has been updated.");
 | 
			
		||||
 | 
			
		||||
    // Ensure the content was not immediately published.
 | 
			
		||||
    $this->assertSession()->linkExists('Test menu link');
 | 
			
		||||
 | 
			
		||||
    // Publish the node and ensure the new link text was published.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'moderation_state[0][state]' => 'published',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertSession()->linkExists('Test menu link draft');
 | 
			
		||||
 | 
			
		||||
    // Try to save a new non-default (draft) revision without any changes and
 | 
			
		||||
    // check that the error message is not shown.
 | 
			
		||||
    $edit = ['moderation_state[0][state]' => 'draft'];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
 | 
			
		||||
    // Create a node.
 | 
			
		||||
    $node = $this->drupalCreateNode();
 | 
			
		||||
 | 
			
		||||
    // Publish the node with no changes.
 | 
			
		||||
    $edit = ['moderation_state[0][state]' => 'published'];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertSession()->pageTextContains("Page {$node->label()} has been updated.");
 | 
			
		||||
 | 
			
		||||
    // Add a menu link and save and create a new non-default (draft) revision
 | 
			
		||||
    // and ensure it's not immediately published.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu[enabled]' => 1,
 | 
			
		||||
      'menu[title]' => 'Second test menu link',
 | 
			
		||||
      'moderation_state[0][state]' => 'draft',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertSession()->pageTextContains("Page {$node->label()} has been updated.");
 | 
			
		||||
 | 
			
		||||
    // The link is created to the latest page, which the editor is allowed
 | 
			
		||||
    // see, but an anonymous visitor not.
 | 
			
		||||
    $this->assertSession()->linkExists('Second test menu link');
 | 
			
		||||
    $this->drupalLogout();
 | 
			
		||||
    $this->assertSession()->linkNotExists('Second test menu link');
 | 
			
		||||
 | 
			
		||||
    $this->drupalLogin($editor);
 | 
			
		||||
    // Publish the content and ensure the new menu link shows up.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'moderation_state[0][state]' => 'published',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertSession()->pageTextContains("Page {$node->label()} has been updated.");
 | 
			
		||||
    $this->assertSession()->linkExists('Second test menu link');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests that unpublished content can be selected through the menu UI.
 | 
			
		||||
   */
 | 
			
		||||
  public function testMenuUiWithUnpublishedContent(): void {
 | 
			
		||||
    $editor_with_unpublished_content_access = $this->drupalCreateUser([
 | 
			
		||||
      'administer nodes',
 | 
			
		||||
      'administer menu',
 | 
			
		||||
      'create page content',
 | 
			
		||||
      'use editorial transition create_new_draft',
 | 
			
		||||
      'view any unpublished content',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->drupalLogin($editor_with_unpublished_content_access);
 | 
			
		||||
 | 
			
		||||
    // Create a node.
 | 
			
		||||
    $node_title = $this->randomMachineName();
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'title[0][value]' => $node_title,
 | 
			
		||||
      'menu[enabled]' => 1,
 | 
			
		||||
      'menu[title]' => $node_title,
 | 
			
		||||
      'moderation_state[0][state]' => 'draft',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/add/page');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
 | 
			
		||||
    // Assert that the unpublished node can be selected as a parent menu link
 | 
			
		||||
    // for users with access to the node.
 | 
			
		||||
    $node = $this->drupalGetNodeByTitle($node_title);
 | 
			
		||||
    $this->assertTrue($node->access('view', $editor_with_unpublished_content_access));
 | 
			
		||||
    $this->assertEquals($edit['title[0][value]'], $node->getTitle());
 | 
			
		||||
    $this->drupalGet('node/add/page');
 | 
			
		||||
    $link_id = menu_ui_get_menu_link_defaults($node)['entity_id'];
 | 
			
		||||
    /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $link */
 | 
			
		||||
    $link = MenuLinkContent::load($link_id);
 | 
			
		||||
    $this->assertSession()->optionExists('edit-menu-menu-parent', 'main:' . $link->getPluginId());
 | 
			
		||||
 | 
			
		||||
    // Assert that the unpublished node cannot be selected as a parent menu link
 | 
			
		||||
    // for users without access to the node.
 | 
			
		||||
    $editor_without_unpublished_content_access = $this->drupalCreateUser([
 | 
			
		||||
      'administer nodes',
 | 
			
		||||
      'administer menu',
 | 
			
		||||
      'create page content',
 | 
			
		||||
      'use editorial transition create_new_draft',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->drupalLogin($editor_without_unpublished_content_access);
 | 
			
		||||
    $this->assertFalse($node->access('view', $editor_without_unpublished_content_access));
 | 
			
		||||
    $this->drupalGet('node/add/page');
 | 
			
		||||
    $this->assertSession()->optionNotExists('edit-menu-menu-parent', 'main:' . $link->getPluginId());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,175 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Functional;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Language\LanguageInterface;
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use Drupal\Tests\language\Traits\LanguageTestTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests Menu UI and Content Translation integration for content entities.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MenuUiContentTranslationTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  use LanguageTestTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = [
 | 
			
		||||
    'block',
 | 
			
		||||
    'language',
 | 
			
		||||
    'content_translation',
 | 
			
		||||
    'menu_ui',
 | 
			
		||||
    'node',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
 | 
			
		||||
    // Place menu block and local tasks block.
 | 
			
		||||
    $this->drupalPlaceBlock('system_menu_block:main');
 | 
			
		||||
    $this->drupalPlaceBlock('local_tasks_block');
 | 
			
		||||
 | 
			
		||||
    // Create a 'page' content type.
 | 
			
		||||
    $this->drupalCreateContentType([
 | 
			
		||||
      'type' => 'page',
 | 
			
		||||
      'name' => 'Basic page',
 | 
			
		||||
      'display_submitted' => FALSE,
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Add a second language.
 | 
			
		||||
    static::createLanguageFromLangcode('de');
 | 
			
		||||
 | 
			
		||||
    // Create an account and login.
 | 
			
		||||
    $user = $this->drupalCreateUser([
 | 
			
		||||
      'administer site configuration',
 | 
			
		||||
      'administer nodes',
 | 
			
		||||
      'create page content',
 | 
			
		||||
      'edit any page content',
 | 
			
		||||
      'delete any page content',
 | 
			
		||||
      'administer content translation',
 | 
			
		||||
      'translate any entity',
 | 
			
		||||
      'create content translations',
 | 
			
		||||
      'administer languages',
 | 
			
		||||
      'administer content types',
 | 
			
		||||
      'administer menu',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->drupalLogin($user);
 | 
			
		||||
 | 
			
		||||
    // Enable translation for page nodes and menu link content.
 | 
			
		||||
    static::enableBundleTranslation('node', 'page');
 | 
			
		||||
    static::enableBundleTranslation('menu_link_content', 'menu_link_content');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Gets a content entity object by title.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $entity_type_id
 | 
			
		||||
   *   Id of content entity type of content entity to load.
 | 
			
		||||
   * @param string $title
 | 
			
		||||
   *   Title of content entity to load.
 | 
			
		||||
   *
 | 
			
		||||
   * @return \Drupal\Core\Entity\ContentEntityInterface
 | 
			
		||||
   *   First found content entity with given title.
 | 
			
		||||
   */
 | 
			
		||||
  protected function getContentEntityByTitle($entity_type_id, $title) {
 | 
			
		||||
    $entity_type_manager = $this->container->get('entity_type.manager');
 | 
			
		||||
    $storage = $entity_type_manager->getStorage($entity_type_id);
 | 
			
		||||
    $storage->resetCache();
 | 
			
		||||
    $entities = $storage->loadByProperties([
 | 
			
		||||
      'title' => $title,
 | 
			
		||||
    ]);
 | 
			
		||||
    return reset($entities);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Provides test data sets for testChangeContentToPseudoLanguage().
 | 
			
		||||
   *
 | 
			
		||||
   * @return array
 | 
			
		||||
   *   Data sets to test keyed by data set label.
 | 
			
		||||
   */
 | 
			
		||||
  public static function provideChangeContentToPseudoLanguageData() {
 | 
			
		||||
    return [
 | 
			
		||||
      'und' => ['langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED],
 | 
			
		||||
      'zxx' => ['langcode' => LanguageInterface::LANGCODE_NOT_APPLICABLE],
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests changing content with menu link from language to pseudo language.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $langcode
 | 
			
		||||
   *   Language code of pseudo-language to change content language to.
 | 
			
		||||
   *   Either \Drupal\Core\LanguageInterface::LANGCODE_NOT_SPECIFIED or
 | 
			
		||||
   *   \Drupal\Core\LanguageInterface::LANGCODE_NOT_APPLICABLE.
 | 
			
		||||
   *
 | 
			
		||||
   * @dataProvider provideChangeContentToPseudoLanguageData
 | 
			
		||||
   */
 | 
			
		||||
  public function testChangeContentToPseudoLanguage($langcode): void {
 | 
			
		||||
    $node_title = 'Test node';
 | 
			
		||||
    $menu_link_title_en = 'Test menu link EN';
 | 
			
		||||
    $menu_link_title_pseudo = 'Test menu link PSEUDO';
 | 
			
		||||
 | 
			
		||||
    // Create a page node in English.
 | 
			
		||||
    $this->drupalGet('node/add/page');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'title[0][value]' => $node_title,
 | 
			
		||||
      'menu[enabled]' => 1,
 | 
			
		||||
      'menu[title]' => $menu_link_title_en,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
 | 
			
		||||
    // Assert that node exists and node language is English.
 | 
			
		||||
    $node = $this->getContentEntityByTitle('node', $node_title);
 | 
			
		||||
    $this->assertTrue(is_object($node));
 | 
			
		||||
    $this->assertTrue($node->language()->getId() == 'en');
 | 
			
		||||
 | 
			
		||||
    // Assert that menu link exists and menu link language is English.
 | 
			
		||||
    $menu_link = $this->getContentEntityByTitle('menu_link_content', $menu_link_title_en);
 | 
			
		||||
    $this->assertTrue(is_object($menu_link));
 | 
			
		||||
    $this->assertTrue($menu_link->language()->getId() == 'en');
 | 
			
		||||
    $this->assertTrue($menu_link->hasTranslation('en'));
 | 
			
		||||
 | 
			
		||||
    // Assert that menu link is visible with initial title.
 | 
			
		||||
    $this->assertSession()->linkExists($menu_link_title_en);
 | 
			
		||||
 | 
			
		||||
    // Change language of page node and title of its menu link.
 | 
			
		||||
    $this->clickLink('Edit');
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'langcode[0][value]' => $langcode,
 | 
			
		||||
      'menu[title]' => $menu_link_title_pseudo,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
 | 
			
		||||
    // Assert that node exists and node language is target language.
 | 
			
		||||
    $node = $this->getContentEntityByTitle('node', $node_title);
 | 
			
		||||
    $this->assertTrue(is_object($node));
 | 
			
		||||
    $this->assertTrue($node->language()->getId() == $langcode);
 | 
			
		||||
 | 
			
		||||
    // Assert that menu link exists and menu link language is target language.
 | 
			
		||||
    $menu_link = $this->getContentEntityByTitle('menu_link_content', $menu_link_title_pseudo);
 | 
			
		||||
    $this->assertTrue(is_object($menu_link));
 | 
			
		||||
    $this->assertTrue($menu_link->language()->getId() == $langcode);
 | 
			
		||||
    $this->assertFalse($menu_link->hasTranslation('en'));
 | 
			
		||||
 | 
			
		||||
    // Assert that menu link is visible with updated title.
 | 
			
		||||
    $this->assertSession()->linkExists($menu_link_title_pseudo);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,155 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Functional;
 | 
			
		||||
 | 
			
		||||
use Drupal\language\Entity\ConfigurableLanguage;
 | 
			
		||||
use Drupal\language\Entity\ContentLanguageSettings;
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use Drupal\Tests\menu_ui\Traits\MenuUiTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests for menu_ui language settings.
 | 
			
		||||
 *
 | 
			
		||||
 * Create menu and menu links in non-English language, and edit language
 | 
			
		||||
 * settings.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MenuUiLanguageTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  use MenuUiTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = [
 | 
			
		||||
    'language',
 | 
			
		||||
    'menu_link_content',
 | 
			
		||||
    'menu_ui',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
 | 
			
		||||
    $this->drupalLogin($this->drupalCreateUser([
 | 
			
		||||
      'access administration pages',
 | 
			
		||||
      'administer menu',
 | 
			
		||||
    ]));
 | 
			
		||||
 | 
			
		||||
    // Add some custom languages.
 | 
			
		||||
    foreach (['aa', 'bb', 'cc', 'cs'] as $language_code) {
 | 
			
		||||
      ConfigurableLanguage::create([
 | 
			
		||||
        'id' => $language_code,
 | 
			
		||||
        'label' => $this->randomMachineName(),
 | 
			
		||||
      ])->save();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests menu language settings and the defaults for menu link items.
 | 
			
		||||
   */
 | 
			
		||||
  public function testMenuLanguage(): void {
 | 
			
		||||
    // Create a test menu to test the various language-related settings.
 | 
			
		||||
    // Machine name has to be lowercase.
 | 
			
		||||
    $menu_name = $this->randomMachineName(16);
 | 
			
		||||
    $label = $this->randomString();
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'id' => $menu_name,
 | 
			
		||||
      'description' => '',
 | 
			
		||||
      'label' => $label,
 | 
			
		||||
      'langcode' => 'aa',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('admin/structure/menu/add');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    ContentLanguageSettings::loadByEntityTypeBundle('menu_link_content', 'menu_link_content')
 | 
			
		||||
      ->setDefaultLangcode('bb')
 | 
			
		||||
      ->setLanguageAlterable(TRUE)
 | 
			
		||||
      ->save();
 | 
			
		||||
 | 
			
		||||
    // Check menu language.
 | 
			
		||||
    $this->assertTrue($this->assertSession()->optionExists('edit-langcode', $edit['langcode'])->isSelected());
 | 
			
		||||
 | 
			
		||||
    // Test menu link language.
 | 
			
		||||
    $link_path = '/';
 | 
			
		||||
 | 
			
		||||
    // Add a menu link.
 | 
			
		||||
    $link_title = $this->randomString();
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'title[0][value]' => $link_title,
 | 
			
		||||
      'link[0][uri]' => $link_path,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet("admin/structure/menu/manage/{$menu_name}/add");
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    // Check the link was added with the correct menu link default language.
 | 
			
		||||
    $menu_links = \Drupal::entityTypeManager()->getStorage('menu_link_content')->loadByProperties(['title' => $link_title]);
 | 
			
		||||
    $menu_link = reset($menu_links);
 | 
			
		||||
    $this->assertMenuLink([
 | 
			
		||||
      'menu_name' => $menu_name,
 | 
			
		||||
      'route_name' => '<front>',
 | 
			
		||||
      'langcode' => 'bb',
 | 
			
		||||
    ], $menu_link->getPluginId());
 | 
			
		||||
 | 
			
		||||
    // Edit menu link default, changing it to cc.
 | 
			
		||||
    ContentLanguageSettings::loadByEntityTypeBundle('menu_link_content', 'menu_link_content')
 | 
			
		||||
      ->setDefaultLangcode('cc')
 | 
			
		||||
      ->setLanguageAlterable(TRUE)
 | 
			
		||||
      ->save();
 | 
			
		||||
 | 
			
		||||
    // Add a menu link.
 | 
			
		||||
    $link_title = $this->randomString();
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'title[0][value]' => $link_title,
 | 
			
		||||
      'link[0][uri]' => $link_path,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet("admin/structure/menu/manage/{$menu_name}/add");
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    // Check the link was added with the correct new menu link default language.
 | 
			
		||||
    $menu_links = \Drupal::entityTypeManager()->getStorage('menu_link_content')->loadByProperties(['title' => $link_title]);
 | 
			
		||||
    $menu_link = reset($menu_links);
 | 
			
		||||
    $this->assertMenuLink([
 | 
			
		||||
      'menu_name' => $menu_name,
 | 
			
		||||
      'route_name' => '<front>',
 | 
			
		||||
      'langcode' => 'cc',
 | 
			
		||||
    ], $menu_link->getPluginId());
 | 
			
		||||
 | 
			
		||||
    // Now change the language of the new link to 'bb'.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'langcode[0][value]' => 'bb',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('admin/structure/menu/item/' . $menu_link->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertMenuLink([
 | 
			
		||||
      'menu_name' => $menu_name,
 | 
			
		||||
      'route_name' => '<front>',
 | 
			
		||||
      'langcode' => 'bb',
 | 
			
		||||
    ], $menu_link->getPluginId());
 | 
			
		||||
 | 
			
		||||
    // Saving menu link items ends up on the edit menu page. To check the menu
 | 
			
		||||
    // link has the correct language default on edit, go to the menu link edit
 | 
			
		||||
    // page first.
 | 
			
		||||
    $this->drupalGet('admin/structure/menu/item/' . $menu_link->id() . '/edit');
 | 
			
		||||
    // Check that the language selector has the correct default value.
 | 
			
		||||
    $this->assertTrue($this->assertSession()->optionExists('edit-langcode-0-value', 'bb')->isSelected());
 | 
			
		||||
 | 
			
		||||
    // Edit menu to hide the language select on menu link item add.
 | 
			
		||||
    ContentLanguageSettings::loadByEntityTypeBundle('menu_link_content', 'menu_link_content')
 | 
			
		||||
      ->setDefaultLangcode('cc')
 | 
			
		||||
      ->setLanguageAlterable(FALSE)
 | 
			
		||||
      ->save();
 | 
			
		||||
 | 
			
		||||
    // Check that the language selector is not available on menu link add page.
 | 
			
		||||
    $this->drupalGet("admin/structure/menu/manage/$menu_name/add");
 | 
			
		||||
    $this->assertSession()->fieldNotExists('edit-langcode-0-value');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,88 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Functional;
 | 
			
		||||
 | 
			
		||||
use Drupal\menu_link_content\Entity\MenuLinkContent;
 | 
			
		||||
use Drupal\node\Entity\Node;
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Edit a node when you don't have permission to add or edit menu links.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MenuUiNodeAccessTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = [
 | 
			
		||||
    'menu_ui',
 | 
			
		||||
    'test_page_test',
 | 
			
		||||
    'node',
 | 
			
		||||
    'menu_link_access_test',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
 | 
			
		||||
    $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests menu link create access is enforced.
 | 
			
		||||
   */
 | 
			
		||||
  public function testMenuLinkCreateAccess(): void {
 | 
			
		||||
    $this->drupalLogin($this->drupalCreateUser([
 | 
			
		||||
      'administer menu',
 | 
			
		||||
      'edit any page content',
 | 
			
		||||
    ]));
 | 
			
		||||
    $node = Node::create([
 | 
			
		||||
      'type' => 'page',
 | 
			
		||||
      'title' => $this->randomMachineName(),
 | 
			
		||||
      'uid' => $this->rootUser->id(),
 | 
			
		||||
      'status' => 1,
 | 
			
		||||
    ]);
 | 
			
		||||
    $node->save();
 | 
			
		||||
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->assertSession()->elementNotExists('css', 'input[name="menu[title]"]');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests menu link edit/delete access is enforced.
 | 
			
		||||
   */
 | 
			
		||||
  public function testMenuLinkEditAccess(): void {
 | 
			
		||||
    $this->drupalLogin($this->drupalCreateUser([
 | 
			
		||||
      'administer menu',
 | 
			
		||||
      'edit any page content',
 | 
			
		||||
    ]));
 | 
			
		||||
    $mainLinkTitle = $this->randomMachineName();
 | 
			
		||||
    $node = Node::create([
 | 
			
		||||
      'type' => 'page',
 | 
			
		||||
      'title' => $this->randomMachineName(),
 | 
			
		||||
      'uid' => $this->rootUser->id(),
 | 
			
		||||
      'status' => 1,
 | 
			
		||||
    ]);
 | 
			
		||||
    $node->save();
 | 
			
		||||
    MenuLinkContent::create([
 | 
			
		||||
      'link' => [['uri' => 'entity:node/' . $node->id()]],
 | 
			
		||||
      'title' => $mainLinkTitle,
 | 
			
		||||
      'menu_name' => 'main',
 | 
			
		||||
    ])->save();
 | 
			
		||||
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->assertSession()->elementNotExists('css', 'input[name="menu[title]"]');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										469
									
								
								web/core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										469
									
								
								web/core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,469 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Functional;
 | 
			
		||||
 | 
			
		||||
use Drupal\language\Entity\ConfigurableLanguage;
 | 
			
		||||
use Drupal\menu_link_content\Entity\MenuLinkContent;
 | 
			
		||||
use Drupal\node\Entity\Node;
 | 
			
		||||
use Drupal\node\Entity\NodeType;
 | 
			
		||||
use Drupal\system\Entity\Menu;
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use Drupal\Tests\content_translation\Traits\ContentTranslationTestTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add, edit, and delete a node with menu link.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MenuUiNodeTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  use ContentTranslationTestTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * An editor user.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\user\UserInterface
 | 
			
		||||
   */
 | 
			
		||||
  protected $editor;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = [
 | 
			
		||||
    'menu_ui',
 | 
			
		||||
    'test_page_test',
 | 
			
		||||
    'node',
 | 
			
		||||
    'block',
 | 
			
		||||
    'locale',
 | 
			
		||||
    'language',
 | 
			
		||||
    'content_translation',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
 | 
			
		||||
    $this->drupalPlaceBlock('system_menu_block:main');
 | 
			
		||||
    $this->drupalPlaceBlock('page_title_block');
 | 
			
		||||
 | 
			
		||||
    $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
 | 
			
		||||
 | 
			
		||||
    $this->editor = $this->drupalCreateUser([
 | 
			
		||||
      'access administration pages',
 | 
			
		||||
      'administer content types',
 | 
			
		||||
      'administer menu',
 | 
			
		||||
      'create page content',
 | 
			
		||||
      'edit any page content',
 | 
			
		||||
      'delete any page content',
 | 
			
		||||
      'create content translations',
 | 
			
		||||
      'update content translations',
 | 
			
		||||
      'delete content translations',
 | 
			
		||||
      'translate any entity',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->drupalLogin($this->editor);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests creating, editing, deleting menu links via node form widget.
 | 
			
		||||
   */
 | 
			
		||||
  public function testMenuNodeFormWidget(): void {
 | 
			
		||||
    // Verify that cacheability metadata is bubbled from the menu link tree
 | 
			
		||||
    // access checking that is performed when determining the "default parent
 | 
			
		||||
    // item" options in menu_ui_form_node_type_form_alter(). The "log out" link
 | 
			
		||||
    // adds the "user.roles:authenticated" cache context.
 | 
			
		||||
    $this->drupalGet('admin/structure/types/manage/page');
 | 
			
		||||
    $this->assertSession()->responseHeaderContains('X-Drupal-Cache-Contexts', 'user.roles:authenticated');
 | 
			
		||||
 | 
			
		||||
    // Assert the description of "Available menus" checkboxes field.
 | 
			
		||||
    $this->assertSession()->pageTextContains('Content of this type can be placed in the selected menus.');
 | 
			
		||||
 | 
			
		||||
    // Verify that the menu link title has the correct maxlength.
 | 
			
		||||
    $title_max_length = \Drupal::service('entity_field.manager')->getBaseFieldDefinitions('menu_link_content')['title']->getSetting('max_length');
 | 
			
		||||
    $this->drupalGet('node/add/page');
 | 
			
		||||
    $this->assertSession()->responseMatches('/<input .* id="edit-menu-title" .* maxlength="' . $title_max_length . '" .* \/>/');
 | 
			
		||||
 | 
			
		||||
    // Verify that the menu link description has the correct maxlength.
 | 
			
		||||
    $description_max_length = \Drupal::service('entity_field.manager')->getBaseFieldDefinitions('menu_link_content')['description']->getSetting('max_length');
 | 
			
		||||
    $this->drupalGet('node/add/page');
 | 
			
		||||
    $this->assertSession()->responseMatches('/<input .* id="edit-menu-description" .* maxlength="' . $description_max_length . '" .* \/>/');
 | 
			
		||||
 | 
			
		||||
    // Disable the default main menu, so that no menus are enabled.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu_options[main]' => FALSE,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('admin/structure/types/manage/page');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
 | 
			
		||||
    // Verify that no menu settings are displayed and nodes can be created.
 | 
			
		||||
    $this->drupalGet('node/add/page');
 | 
			
		||||
    $this->assertSession()->pageTextContains('Create Basic page');
 | 
			
		||||
    $this->assertSession()->pageTextNotContains('Menu settings');
 | 
			
		||||
    $node_title = $this->randomMachineName();
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'title[0][value]' => $node_title,
 | 
			
		||||
      'body[0][value]' => $this->randomString(),
 | 
			
		||||
    ];
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $node = $this->drupalGetNodeByTitle($node_title);
 | 
			
		||||
    $this->assertEquals($edit['title[0][value]'], $node->getTitle());
 | 
			
		||||
 | 
			
		||||
    // Test that we cannot set a menu item from a menu that is not set as
 | 
			
		||||
    // available.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu_options[tools]' => 1,
 | 
			
		||||
      'menu_parent' => 'main:',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('admin/structure/types/manage/page');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertSession()->pageTextContains('The selected menu link is not under one of the selected menus.');
 | 
			
		||||
    $this->assertSession()->pageTextNotContains("The content type Basic page has been updated.");
 | 
			
		||||
 | 
			
		||||
    // Enable Tools menu as available menu.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu_options[main]' => 1,
 | 
			
		||||
      'menu_options[tools]' => 1,
 | 
			
		||||
      'menu_parent' => 'main:',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('admin/structure/types/manage/page');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertSession()->pageTextContains("The content type Basic page has been updated.");
 | 
			
		||||
 | 
			
		||||
    // Test that we can preview a node that will create a menu item.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'title[0][value]' => $node_title,
 | 
			
		||||
      'menu[enabled]' => 1,
 | 
			
		||||
      'menu[title]' => 'Test preview',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/add/page');
 | 
			
		||||
    $this->submitForm($edit, 'Preview');
 | 
			
		||||
 | 
			
		||||
    // Create a node.
 | 
			
		||||
    $node_title = $this->randomMachineName();
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'title[0][value]' => $node_title,
 | 
			
		||||
      'body[0][value]' => $this->randomString(),
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/add/page');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $node = $this->drupalGetNodeByTitle($node_title);
 | 
			
		||||
    // Assert that there is no link for the node.
 | 
			
		||||
    $this->drupalGet('test-page');
 | 
			
		||||
    $this->assertSession()->linkNotExists($node_title);
 | 
			
		||||
 | 
			
		||||
    // Edit the node, enable the menu link setting, but skip the link title.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu[enabled]' => 1,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    // Assert that there is a link for the node.
 | 
			
		||||
    $this->drupalGet('test-page');
 | 
			
		||||
    $this->assertSession()->linkExists($node_title);
 | 
			
		||||
 | 
			
		||||
    // Make sure the menu links only appear when the node is published.
 | 
			
		||||
    // These buttons just appear for 'administer nodes' users.
 | 
			
		||||
    $admin_user = $this->drupalCreateUser([
 | 
			
		||||
      'access administration pages',
 | 
			
		||||
      'administer content types',
 | 
			
		||||
      'administer nodes',
 | 
			
		||||
      'administer menu',
 | 
			
		||||
      'create page content',
 | 
			
		||||
      'edit any page content',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->drupalLogin($admin_user);
 | 
			
		||||
    // Assert that the link does not exist if unpublished.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu[enabled]' => 1,
 | 
			
		||||
      'menu[title]' => $node_title,
 | 
			
		||||
      'status[value]' => FALSE,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->drupalGet('test-page');
 | 
			
		||||
    $this->assertSession()->linkNotExists($node_title, 'Found no menu link with the node unpublished');
 | 
			
		||||
    // Assert that the link exists if published.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'status[value]' => TRUE,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->drupalGet('test-page');
 | 
			
		||||
    $this->assertSession()->linkExists($node_title, 0, 'Found a menu link with the node published');
 | 
			
		||||
 | 
			
		||||
    // Log back in as normal user.
 | 
			
		||||
    $this->drupalLogin($this->editor);
 | 
			
		||||
    // Edit the node and create a menu link.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu[enabled]' => 1,
 | 
			
		||||
      'menu[title]' => $node_title,
 | 
			
		||||
      'menu[weight]' => 17,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    // Assert that the link exists.
 | 
			
		||||
    $this->drupalGet('test-page');
 | 
			
		||||
    $this->assertSession()->linkExists($node_title);
 | 
			
		||||
    // Check if menu weight is 17.
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->assertSession()->fieldValueEquals('edit-menu-weight', 17);
 | 
			
		||||
    // Verify that the menu link title field has correct maxlength in node edit
 | 
			
		||||
    // form.
 | 
			
		||||
    $this->assertSession()->responseMatches('/<input .* id="edit-menu-title" .* maxlength="' . $title_max_length . '" .* \/>/');
 | 
			
		||||
    // Verify that the menu link description field has correct maxlength in
 | 
			
		||||
    // node add form.
 | 
			
		||||
    $this->assertSession()->responseMatches('/<input .* id="edit-menu-description" .* maxlength="' . $description_max_length . '" .* \/>/');
 | 
			
		||||
 | 
			
		||||
    // Disable the menu link, then edit the node--the link should stay disabled.
 | 
			
		||||
    $link_id = menu_ui_get_menu_link_defaults($node)['entity_id'];
 | 
			
		||||
    /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $link */
 | 
			
		||||
    $link = MenuLinkContent::load($link_id);
 | 
			
		||||
    $link->set('enabled', FALSE);
 | 
			
		||||
    $link->save();
 | 
			
		||||
    $this->drupalGet($node->toUrl('edit-form'));
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $link = MenuLinkContent::load($link_id);
 | 
			
		||||
    $this->assertFalse($link->isEnabled(), 'Saving a node with a disabled menu link keeps the menu link disabled.');
 | 
			
		||||
 | 
			
		||||
    // Edit the node and remove the menu link.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu[enabled]' => FALSE,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    // Assert that there is no link for the node.
 | 
			
		||||
    $this->drupalGet('test-page');
 | 
			
		||||
    $this->assertSession()->linkNotExists($node_title);
 | 
			
		||||
 | 
			
		||||
    // Add a menu link to the Administration menu.
 | 
			
		||||
    $item = MenuLinkContent::create([
 | 
			
		||||
      'link' => [['uri' => 'entity:node/' . $node->id()]],
 | 
			
		||||
      'title' => $this->randomMachineName(16),
 | 
			
		||||
      'menu_name' => 'admin',
 | 
			
		||||
    ]);
 | 
			
		||||
    $item->save();
 | 
			
		||||
 | 
			
		||||
    // Assert that disabled Administration menu is not shown on the
 | 
			
		||||
    // node/$nid/edit page.
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->assertSession()->pageTextContains('Provide a menu link');
 | 
			
		||||
    // Assert that the link is still in the Administration menu after save.
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $link = MenuLinkContent::load($item->id());
 | 
			
		||||
    $this->assertInstanceOf(MenuLinkContent::class, $link);
 | 
			
		||||
 | 
			
		||||
    // Move the menu link back to the Tools menu.
 | 
			
		||||
    $item->menu_name->value = 'tools';
 | 
			
		||||
    $item->save();
 | 
			
		||||
    // Create a second node.
 | 
			
		||||
    $child_node = $this->drupalCreateNode(['type' => 'article']);
 | 
			
		||||
    // Assign a menu link to the second node, being a child of the first one.
 | 
			
		||||
    $child_item = MenuLinkContent::create([
 | 
			
		||||
      'link' => [['uri' => 'entity:node/' . $child_node->id()]],
 | 
			
		||||
      'title' => $this->randomMachineName(16),
 | 
			
		||||
      'parent' => $item->getPluginId(),
 | 
			
		||||
      'menu_name' => $item->getMenuName(),
 | 
			
		||||
    ]);
 | 
			
		||||
    $child_item->save();
 | 
			
		||||
    // Edit the first node.
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    // Assert that it is not possible to set the parent of the first node to
 | 
			
		||||
    // itself or the second node.
 | 
			
		||||
    $this->assertSession()->optionNotExists('edit-menu-menu-parent', 'tools:' . $item->getPluginId());
 | 
			
		||||
    $this->assertSession()->optionNotExists('edit-menu-menu-parent', 'tools:' . $child_item->getPluginId());
 | 
			
		||||
    // Assert that disallowed Administration menu is not available in options.
 | 
			
		||||
    $this->assertSession()->optionNotExists('edit-menu-menu-parent', 'admin:');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Testing correct loading and saving of menu links via node form widget in a multilingual environment.
 | 
			
		||||
   */
 | 
			
		||||
  public function testMultilingualMenuNodeFormWidget(): void {
 | 
			
		||||
    // Setup languages.
 | 
			
		||||
    $langcodes = ['de'];
 | 
			
		||||
    foreach ($langcodes as $langcode) {
 | 
			
		||||
      static::createLanguageFromLangcode($langcode);
 | 
			
		||||
    }
 | 
			
		||||
    array_unshift($langcodes, \Drupal::languageManager()->getDefaultLanguage()->getId());
 | 
			
		||||
 | 
			
		||||
    $config = \Drupal::service('config.factory')->getEditable('language.negotiation');
 | 
			
		||||
    // Ensure path prefix is used to determine the language.
 | 
			
		||||
    $config->set('url.source', 'path_prefix');
 | 
			
		||||
    // Ensure that there's a path prefix set for english as well.
 | 
			
		||||
    $config->set('url.prefixes.' . $langcodes[0], $langcodes[0]);
 | 
			
		||||
    $config->save();
 | 
			
		||||
 | 
			
		||||
    $languages = [];
 | 
			
		||||
    foreach ($langcodes as $langcode) {
 | 
			
		||||
      $languages[$langcode] = ConfigurableLanguage::load($langcode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Enable translation for pages and menu link content..
 | 
			
		||||
    $this->enableContentTranslation('node', 'page');
 | 
			
		||||
    $this->enableContentTranslation('menu_link_content', 'menu_link_content');
 | 
			
		||||
 | 
			
		||||
    $this->rebuildContainer();
 | 
			
		||||
 | 
			
		||||
    // Create a node.
 | 
			
		||||
    $node_title = $this->randomMachineName(8);
 | 
			
		||||
    $node = Node::create([
 | 
			
		||||
      'type' => 'page',
 | 
			
		||||
      'title' => $node_title,
 | 
			
		||||
      'body' => $this->randomMachineName(16),
 | 
			
		||||
      'uid' => $this->editor->id(),
 | 
			
		||||
      'status' => 1,
 | 
			
		||||
      'langcode' => $langcodes[0],
 | 
			
		||||
    ]);
 | 
			
		||||
    $node->save();
 | 
			
		||||
 | 
			
		||||
    // Create translation.
 | 
			
		||||
    $translated_node_title = $this->randomMachineName(8);
 | 
			
		||||
    $node->addTranslation($langcodes[1], ['title' => $translated_node_title, 'body' => $this->randomMachineName(16), 'status' => 1]);
 | 
			
		||||
    $node->save();
 | 
			
		||||
 | 
			
		||||
    // Edit the node and create a menu link.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu[enabled]' => 1,
 | 
			
		||||
      'menu[title]' => $node_title,
 | 
			
		||||
      'menu[weight]' => 17,
 | 
			
		||||
    ];
 | 
			
		||||
    $options = ['language' => $languages[$langcodes[0]]];
 | 
			
		||||
    $url = $node->toUrl('edit-form', $options);
 | 
			
		||||
    $this->drupalGet($url);
 | 
			
		||||
    $this->submitForm($edit, 'Save (this translation)');
 | 
			
		||||
 | 
			
		||||
    // Edit the node in a different language and translate the menu link.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'menu[enabled]' => 1,
 | 
			
		||||
      'menu[title]' => $translated_node_title,
 | 
			
		||||
      'menu[weight]' => 17,
 | 
			
		||||
    ];
 | 
			
		||||
    $options = ['language' => $languages[$langcodes[1]]];
 | 
			
		||||
    $url = $node->toUrl('edit-form', $options);
 | 
			
		||||
    $this->drupalGet($url);
 | 
			
		||||
    $this->submitForm($edit, 'Save (this translation)');
 | 
			
		||||
 | 
			
		||||
    // Assert that the original link exists in the frontend.
 | 
			
		||||
    $this->drupalGet('node/' . $node->id(), ['language' => $languages[$langcodes[0]]]);
 | 
			
		||||
    $this->assertSession()->linkExists($node_title);
 | 
			
		||||
 | 
			
		||||
    // Assert that the translated link exists in the frontend.
 | 
			
		||||
    $this->drupalGet('node/' . $node->id(), ['language' => $languages[$langcodes[1]]]);
 | 
			
		||||
    $this->assertSession()->linkExists($translated_node_title);
 | 
			
		||||
 | 
			
		||||
    // Revisit the edit page in original language, check the loaded menu item
 | 
			
		||||
    // title and save.
 | 
			
		||||
    $options = ['language' => $languages[$langcodes[0]]];
 | 
			
		||||
    $url = $node->toUrl('edit-form', $options);
 | 
			
		||||
    $this->drupalGet($url);
 | 
			
		||||
    $this->assertSession()->fieldValueEquals('edit-menu-title', $node_title);
 | 
			
		||||
    $this->submitForm([], 'Save (this translation)');
 | 
			
		||||
 | 
			
		||||
    // Revisit the edit page of the translation and check the loaded menu item
 | 
			
		||||
    // title.
 | 
			
		||||
    $options = ['language' => $languages[$langcodes[1]]];
 | 
			
		||||
    $url = $node->toUrl('edit-form', $options);
 | 
			
		||||
    $this->drupalGet($url);
 | 
			
		||||
    $this->assertSession()->fieldValueEquals('edit-menu-title', $translated_node_title);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests creating menu links via node form widget for nodes with grants.
 | 
			
		||||
   */
 | 
			
		||||
  public function testMenuNodeWithGrantsFormWidget(): void {
 | 
			
		||||
    \Drupal::service('module_installer')->install(['node_access_test']);
 | 
			
		||||
    node_access_rebuild();
 | 
			
		||||
    $this->assertTrue(\Drupal::moduleHandler()->hasImplementations('node_grants'));
 | 
			
		||||
 | 
			
		||||
    $admin_user = $this->drupalCreateUser([
 | 
			
		||||
      'access administration pages',
 | 
			
		||||
      'administer content types',
 | 
			
		||||
      'administer nodes',
 | 
			
		||||
      'administer menu',
 | 
			
		||||
      'create page content',
 | 
			
		||||
      'edit any page content',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->drupalLogin($admin_user);
 | 
			
		||||
 | 
			
		||||
    $node_title = $this->randomMachineName();
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'title[0][value]' => $node_title,
 | 
			
		||||
      'menu[enabled]' => 1,
 | 
			
		||||
      'menu[title]' => $node_title,
 | 
			
		||||
      'status[value]' => 0,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/add/page');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
 | 
			
		||||
    $node = $this->drupalGetNodeByTitle($node_title);
 | 
			
		||||
    $this->assertTrue($node->access('view', $admin_user));
 | 
			
		||||
    $this->drupalGet('node/add/page');
 | 
			
		||||
    $link_id = menu_ui_get_menu_link_defaults($node)['entity_id'];
 | 
			
		||||
    /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $link */
 | 
			
		||||
    $link = MenuLinkContent::load($link_id);
 | 
			
		||||
    $this->assertSession()->optionExists('edit-menu-menu-parent', 'main:' . $link->getPluginId());
 | 
			
		||||
 | 
			
		||||
    // Assert that the unpublished node cannot be selected as a parent menu link
 | 
			
		||||
    // for users without access to the node.
 | 
			
		||||
    $admin_user_without_content_access = $this->drupalCreateUser([
 | 
			
		||||
      'access administration pages',
 | 
			
		||||
      'administer content types',
 | 
			
		||||
      'administer nodes',
 | 
			
		||||
      'administer menu',
 | 
			
		||||
      'create page content',
 | 
			
		||||
      'edit any page content',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->drupalLogin($admin_user_without_content_access);
 | 
			
		||||
    $this->assertFalse($node->access('view', $admin_user_without_content_access));
 | 
			
		||||
    $this->drupalGet('node/add/page');
 | 
			
		||||
    $this->assertSession()->optionNotExists('edit-menu-menu-parent', 'main:' . $link->getPluginId());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests main menu links are prioritized when editing nodes.
 | 
			
		||||
   *
 | 
			
		||||
   * @see menu_ui_get_menu_link_defaults()
 | 
			
		||||
   */
 | 
			
		||||
  public function testMainMenuIsPrioritized(): void {
 | 
			
		||||
    $this->drupalLogin($this->drupalCreateUser([
 | 
			
		||||
      'administer menu',
 | 
			
		||||
      'edit any page content',
 | 
			
		||||
    ]));
 | 
			
		||||
    $menu_name = $this->randomMachineName();
 | 
			
		||||
    $mainLinkTitle = $this->randomMachineName();
 | 
			
		||||
    $nonMainLinkTitle = $this->randomMachineName();
 | 
			
		||||
    Menu::create(['id' => $menu_name, 'label' => $menu_name])->save();
 | 
			
		||||
    $nodeType = NodeType::load('page');
 | 
			
		||||
    $nodeType->setThirdPartySetting('menu_ui', 'available_menus', [$menu_name, 'main'])->save();
 | 
			
		||||
    $node = Node::create([
 | 
			
		||||
      'type' => 'page',
 | 
			
		||||
      'title' => $this->randomMachineName(),
 | 
			
		||||
      'uid' => $this->rootUser->id(),
 | 
			
		||||
      'status' => 1,
 | 
			
		||||
    ]);
 | 
			
		||||
    $node->save();
 | 
			
		||||
    MenuLinkContent::create([
 | 
			
		||||
      'link' => [['uri' => 'entity:node/' . $node->id()]],
 | 
			
		||||
      'title' => $nonMainLinkTitle,
 | 
			
		||||
      'menu_name' => $menu_name,
 | 
			
		||||
    ])->save();
 | 
			
		||||
    MenuLinkContent::create([
 | 
			
		||||
      'link' => [['uri' => 'entity:node/' . $node->id()]],
 | 
			
		||||
      'title' => $mainLinkTitle,
 | 
			
		||||
      'menu_name' => 'main',
 | 
			
		||||
    ])->save();
 | 
			
		||||
    $this->drupalGet('node/' . $node->id() . '/edit');
 | 
			
		||||
    $element = $this->assertSession()->elementExists('css', 'input[name="menu[title]"]');
 | 
			
		||||
    $this->assertEquals($mainLinkTitle, $element->getValue());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1283
									
								
								web/core/modules/menu_ui/tests/src/Functional/MenuUiTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1283
									
								
								web/core/modules/menu_ui/tests/src/Functional/MenuUiTest.php
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Functional;
 | 
			
		||||
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use Drupal\system\Entity\Menu;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests that uninstalling menu does not remove custom menus.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MenuUninstallTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['menu_ui'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests Menu uninstall.
 | 
			
		||||
   */
 | 
			
		||||
  public function testMenuUninstall(): void {
 | 
			
		||||
    \Drupal::service('module_installer')->uninstall(['menu_ui']);
 | 
			
		||||
 | 
			
		||||
    \Drupal::entityTypeManager()->getStorage('menu')->resetCache(['admin']);
 | 
			
		||||
 | 
			
		||||
    $this->assertNotEmpty(Menu::load('admin'), 'The \'admin\' menu still exists after uninstalling Menu UI module.');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,165 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\FunctionalJavascript;
 | 
			
		||||
 | 
			
		||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
 | 
			
		||||
use Drupal\system\Entity\Menu;
 | 
			
		||||
use Drupal\system\MenuStorage;
 | 
			
		||||
use Drupal\Tests\contextual\FunctionalJavascript\ContextualLinkClickTrait;
 | 
			
		||||
use Drupal\Tests\menu_ui\Traits\MenuUiTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests custom menu and menu links operations using the UI.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MenuUiJavascriptTest extends WebDriverTestBase {
 | 
			
		||||
 | 
			
		||||
  use ContextualLinkClickTrait;
 | 
			
		||||
  use MenuUiTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = [
 | 
			
		||||
    'block',
 | 
			
		||||
    'contextual',
 | 
			
		||||
    'menu_link_content',
 | 
			
		||||
    'menu_ui',
 | 
			
		||||
    'test_page_test',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests the contextual links on a menu block.
 | 
			
		||||
   */
 | 
			
		||||
  public function testBlockContextualLinks(): void {
 | 
			
		||||
    $this->drupalLogin($this->drupalCreateUser([
 | 
			
		||||
      'administer menu',
 | 
			
		||||
      'access contextual links',
 | 
			
		||||
      'administer blocks',
 | 
			
		||||
    ]));
 | 
			
		||||
    $menu = $this->addCustomMenu();
 | 
			
		||||
 | 
			
		||||
    $block = $this->drupalPlaceBlock('system_menu_block:' . $menu->id(), [
 | 
			
		||||
      'label' => 'Custom menu',
 | 
			
		||||
      'provider' => 'system',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->addMenuLink('', '/', $menu->id());
 | 
			
		||||
 | 
			
		||||
    $this->drupalGet('test-page');
 | 
			
		||||
 | 
			
		||||
    // Click on 'Configure block' contextual link.
 | 
			
		||||
    $this->clickContextualLink("#block-{$block->id()}", 'Configure block');
 | 
			
		||||
    // Check that we're on block configuration form.
 | 
			
		||||
    $this->assertNotEmpty($this->getSession()->getPage()->findLink('Remove block'));
 | 
			
		||||
 | 
			
		||||
    $this->drupalGet('test-page');
 | 
			
		||||
 | 
			
		||||
    // Click on 'Edit menu' contextual link.
 | 
			
		||||
    $this->clickContextualLink("#block-{$block->id()}", 'Edit menu');
 | 
			
		||||
    // Check that we're on block configuration form.
 | 
			
		||||
    $this->assertSession()->pageTextContains("Machine name: {$menu->id()}");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Creates a custom menu.
 | 
			
		||||
   *
 | 
			
		||||
   * @return \Drupal\system\Entity\Menu
 | 
			
		||||
   *   The custom menu that has been created.
 | 
			
		||||
   */
 | 
			
		||||
  protected function addCustomMenu() {
 | 
			
		||||
    // Try adding a menu using a menu_name that is too long.
 | 
			
		||||
    $label = $this->randomMachineName(16);
 | 
			
		||||
    $menu_id = $this->randomMachineName(MenuStorage::MAX_ID_LENGTH + 1);
 | 
			
		||||
 | 
			
		||||
    $this->drupalGet('admin/structure/menu/add');
 | 
			
		||||
    $page = $this->getSession()->getPage();
 | 
			
		||||
    // Type the label to activate the machine name field and the edit button.
 | 
			
		||||
    $page->fillField('Title', $label);
 | 
			
		||||
    // Wait for the machine name widget to be activated.
 | 
			
		||||
    $this->assertSession()->waitForElementVisible('css', 'button[type=button].link:contains(Edit)');
 | 
			
		||||
    // Activate the machine name text field.
 | 
			
		||||
    $page->pressButton('Edit');
 | 
			
		||||
    // Try to fill a text longer than the allowed limit.
 | 
			
		||||
    $page->fillField('Menu name', $menu_id);
 | 
			
		||||
    $page->pressButton('Save');
 | 
			
		||||
    // Check that the menu was saved with the ID truncated to the max length.
 | 
			
		||||
    $menu = Menu::load(substr($menu_id, 0, MenuStorage::MAX_ID_LENGTH));
 | 
			
		||||
    $this->assertEquals($label, $menu->label());
 | 
			
		||||
 | 
			
		||||
    // Check that the menu was added.
 | 
			
		||||
    $this->drupalGet('admin/structure/menu');
 | 
			
		||||
    $this->assertSession()->pageTextContains($label);
 | 
			
		||||
 | 
			
		||||
    // Confirm that the custom menu block is available.
 | 
			
		||||
    $this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
 | 
			
		||||
    $this->clickLink('Place block');
 | 
			
		||||
    // Wait for the modal dialog to be loaded.
 | 
			
		||||
    $this->assertSession()->waitForElement('css', "div[aria-describedby=drupal-modal]");
 | 
			
		||||
    // Check that the block is available to be placed.
 | 
			
		||||
    $this->assertSession()->pageTextContains($label);
 | 
			
		||||
 | 
			
		||||
    return $menu;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Adds a menu link using the UI.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $parent
 | 
			
		||||
   *   Optional parent menu link id.
 | 
			
		||||
   * @param string $path
 | 
			
		||||
   *   The path to enter on the form. Defaults to the front page.
 | 
			
		||||
   * @param string $menu_id
 | 
			
		||||
   *   Menu ID. 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 authenticatedUser tests. Defaults
 | 
			
		||||
   *   to FALSE.
 | 
			
		||||
   * @param string $weight
 | 
			
		||||
   *   Menu weight. Defaults to 0.
 | 
			
		||||
   *
 | 
			
		||||
   * @return \Drupal\menu_link_content\Entity\MenuLinkContent
 | 
			
		||||
   *   A menu link entity.
 | 
			
		||||
   */
 | 
			
		||||
  protected function addMenuLink($parent = '', $path = '/', $menu_id = 'tools', $expanded = FALSE, $weight = '0') {
 | 
			
		||||
    // View add menu link page.
 | 
			
		||||
    $this->drupalGet("admin/structure/menu/manage/$menu_id/add");
 | 
			
		||||
 | 
			
		||||
    $title = '!link_' . $this->randomMachineName(16);
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'link[0][uri]' => $path,
 | 
			
		||||
      'title[0][value]' => $title,
 | 
			
		||||
      'description[0][value]' => '',
 | 
			
		||||
      'enabled[value]' => 1,
 | 
			
		||||
      'expanded[value]' => $expanded,
 | 
			
		||||
      'menu_parent' => $menu_id . ':' . $parent,
 | 
			
		||||
      'weight[0][value]' => $weight,
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    // Add menu link.
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertSession()->pageTextContains('The menu link has been saved.');
 | 
			
		||||
 | 
			
		||||
    $storage = $this->container->get('entity_type.manager')->getStorage('menu_link_content');
 | 
			
		||||
    $menu_links = $storage->loadByProperties(['title' => $title]);
 | 
			
		||||
    $menu_link = reset($menu_links);
 | 
			
		||||
 | 
			
		||||
    // Check that the stored menu link meeting the expectations.
 | 
			
		||||
    $this->assertNotNull($menu_link);
 | 
			
		||||
    $this->assertMenuLink([
 | 
			
		||||
      'menu_name' => $menu_id,
 | 
			
		||||
      'children' => [],
 | 
			
		||||
      'parent' => $parent,
 | 
			
		||||
    ], $menu_link->getPluginId());
 | 
			
		||||
 | 
			
		||||
    return $menu_link;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										88
									
								
								web/core/modules/menu_ui/tests/src/Kernel/MenuBlockTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								web/core/modules/menu_ui/tests/src/Kernel/MenuBlockTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,88 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Kernel;
 | 
			
		||||
 | 
			
		||||
use Drupal\KernelTests\KernelTestBase;
 | 
			
		||||
use Drupal\system\Entity\Menu;
 | 
			
		||||
use Drupal\block\Entity\Block;
 | 
			
		||||
use Drupal\system\MenuInterface;
 | 
			
		||||
use Drupal\Tests\user\Traits\UserCreationTrait;
 | 
			
		||||
use Drupal\menu_ui\Hook\MenuUiHooks;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests SystemMenuBlock.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MenuBlockTest extends KernelTestBase {
 | 
			
		||||
 | 
			
		||||
  use UserCreationTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = [
 | 
			
		||||
    'system',
 | 
			
		||||
    'block',
 | 
			
		||||
    'menu_ui',
 | 
			
		||||
    'user',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The menu for testing.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\system\MenuInterface
 | 
			
		||||
   */
 | 
			
		||||
  protected MenuInterface $menu;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
    $this->installEntitySchema('user');
 | 
			
		||||
 | 
			
		||||
    $this->setUpCurrentUser([], ['administer menu']);
 | 
			
		||||
 | 
			
		||||
    // Add a new custom menu.
 | 
			
		||||
    $menu_name = 'mock';
 | 
			
		||||
    $label = $this->randomMachineName(16);
 | 
			
		||||
 | 
			
		||||
    $this->menu = Menu::create([
 | 
			
		||||
      'id' => $menu_name,
 | 
			
		||||
      'label' => $label,
 | 
			
		||||
      'description' => 'Description text',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->menu->save();
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests the editing links for SystemMenuBlock.
 | 
			
		||||
   */
 | 
			
		||||
  public function testOperationLinks(): void {
 | 
			
		||||
    $block = Block::create([
 | 
			
		||||
      'plugin' => 'system_menu_block:' . $this->menu->id(),
 | 
			
		||||
      'region' => 'footer',
 | 
			
		||||
      'id' => 'machine_name',
 | 
			
		||||
      'theme' => 'stark',
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Test when user does have "administer menu" permission.
 | 
			
		||||
    $menuUiEntityOperation = new MenuUiHooks(\Drupal::entityTypeManager());
 | 
			
		||||
    $this->assertEquals([
 | 
			
		||||
      'menu-edit' => [
 | 
			
		||||
        'title' => 'Edit menu',
 | 
			
		||||
        'url' => $this->menu->toUrl('edit-form'),
 | 
			
		||||
        'weight' => 50,
 | 
			
		||||
      ],
 | 
			
		||||
    ], $menuUiEntityOperation->entityOperation($block));
 | 
			
		||||
 | 
			
		||||
    $this->setUpCurrentUser();
 | 
			
		||||
    // Test when user doesn't have "administer menu" permission.
 | 
			
		||||
    $this->assertEmpty($menuUiEntityOperation->entityOperation($block));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								web/core/modules/menu_ui/tests/src/Kernel/MenuDeleteTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								web/core/modules/menu_ui/tests/src/Kernel/MenuDeleteTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,86 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Kernel;
 | 
			
		||||
 | 
			
		||||
use Drupal\KernelTests\KernelTestBase;
 | 
			
		||||
use Drupal\menu_ui\Hook\MenuUiHooks;
 | 
			
		||||
use Drupal\node\Entity\NodeType;
 | 
			
		||||
use Drupal\system\Entity\Menu;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests the menu_delete hook.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MenuDeleteTest extends KernelTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['node', 'menu_ui', 'system'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @covers \Drupal\menu_ui\Hook\MenuUiHooks::menuDelete
 | 
			
		||||
   * @dataProvider providerMenuDelete
 | 
			
		||||
   */
 | 
			
		||||
  public function testMenuDelete($settings, $expected): void {
 | 
			
		||||
    $menu = Menu::create([
 | 
			
		||||
      'id' => 'mock',
 | 
			
		||||
      'label' => $this->randomMachineName(16),
 | 
			
		||||
      'description' => 'Description text',
 | 
			
		||||
    ]);
 | 
			
		||||
    $menu->save();
 | 
			
		||||
    $content_type = NodeType::create([
 | 
			
		||||
      'status' => TRUE,
 | 
			
		||||
      'dependencies' => [
 | 
			
		||||
        'module' => ['menu_ui'],
 | 
			
		||||
      ],
 | 
			
		||||
      'third_party_settings' => [
 | 
			
		||||
        'menu_ui' => $settings,
 | 
			
		||||
      ],
 | 
			
		||||
      'name' => 'Test type',
 | 
			
		||||
      'type' => 'test_type',
 | 
			
		||||
    ]);
 | 
			
		||||
    $content_type->save();
 | 
			
		||||
    $this->assertEquals($settings['available_menus'], $content_type->getThirdPartySetting('menu_ui', 'available_menus'));
 | 
			
		||||
    $this->assertEquals($settings['parent'], $content_type->getThirdPartySetting('menu_ui', 'parent'));
 | 
			
		||||
 | 
			
		||||
    $hooks = new MenuUiHooks(\Drupal::entityTypeManager());
 | 
			
		||||
    $hooks->menuDelete($menu);
 | 
			
		||||
 | 
			
		||||
    $content_type = NodeType::load('test_type');
 | 
			
		||||
    $this->assertEquals($expected['available_menus'], $content_type->getThirdPartySetting('menu_ui', 'available_menus'));
 | 
			
		||||
    $this->assertEquals($expected['parent'], $content_type->getThirdPartySetting('menu_ui', 'parent'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Provides data for testMenuDelete().
 | 
			
		||||
   */
 | 
			
		||||
  public static function providerMenuDelete(): array {
 | 
			
		||||
    return [
 | 
			
		||||
      [
 | 
			
		||||
        ['available_menus' => ['mock'], 'parent' => 'mock:'],
 | 
			
		||||
        ['available_menus' => [], 'parent' => ''],
 | 
			
		||||
      ],
 | 
			
		||||
      [
 | 
			
		||||
        ['available_menus' => ['mock'], 'parent' => 'mock:menu_link_content:e0cd7689-016e-43e4-af8f-7ce82801ab95'],
 | 
			
		||||
        ['available_menus' => [], 'parent' => ''],
 | 
			
		||||
      ],
 | 
			
		||||
      [
 | 
			
		||||
        ['available_menus' => ['main', 'mock'], 'parent' => 'mock:'],
 | 
			
		||||
        ['available_menus' => ['main'], 'parent' => ''],
 | 
			
		||||
      ],
 | 
			
		||||
      [
 | 
			
		||||
        ['available_menus' => ['main'], 'parent' => 'main:'],
 | 
			
		||||
        ['available_menus' => ['main'], 'parent' => 'main:'],
 | 
			
		||||
      ],
 | 
			
		||||
      [
 | 
			
		||||
        ['available_menus' => ['main'], 'parent' => 'main:menu_link_content:e0cd7689-016e-43e4-af8f-7ce82801ab95'],
 | 
			
		||||
        ['available_menus' => ['main'], 'parent' => 'main:menu_link_content:e0cd7689-016e-43e4-af8f-7ce82801ab95'],
 | 
			
		||||
      ],
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,56 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Kernel;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Menu\LocalActionWithDestination;
 | 
			
		||||
use Drupal\KernelTests\KernelTestBase;
 | 
			
		||||
use Drupal\menu_ui\Plugin\Menu\LocalAction\MenuLinkAdd;
 | 
			
		||||
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests \Drupal\menu_ui\Plugin\Menu\LocalAction\MenuLinkAdd deprecation.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 * @group legacy
 | 
			
		||||
 */
 | 
			
		||||
class MenuLinkAddTest extends KernelTestBase {
 | 
			
		||||
 | 
			
		||||
  use ContentTypeCreationTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = [
 | 
			
		||||
    'menu_ui',
 | 
			
		||||
    'menu_link_add_test',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests \Drupal\menu_ui\Plugin\Menu\LocalAction\MenuLinkAdd deprecation.
 | 
			
		||||
   */
 | 
			
		||||
  public function testDeprecation(): void {
 | 
			
		||||
    /** @var \Drupal\Core\Menu\LocalActionManagerInterface $local_action_manager */
 | 
			
		||||
    $local_action_manager = $this->container->get('plugin.manager.menu.local_action');
 | 
			
		||||
 | 
			
		||||
    $this->expectDeprecation('Drupal\menu_ui\Plugin\Menu\LocalAction\MenuLinkAdd is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Menu\LocalActionWithDestination instead. See https://www.drupal.org/node/3490245');
 | 
			
		||||
    $instance = $local_action_manager->createInstance('entity.menu.add_link_form_deprecated');
 | 
			
		||||
    $this->assertInstanceOf(MenuLinkAdd::class, $instance);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests deprecated plugin does not trigger deprecation unless used.
 | 
			
		||||
   */
 | 
			
		||||
  public function testNoDeprecation(): void {
 | 
			
		||||
    /** @var \Drupal\Core\Menu\LocalActionManagerInterface $local_action_manager */
 | 
			
		||||
    $local_action_manager = $this->container->get('plugin.manager.menu.local_action');
 | 
			
		||||
 | 
			
		||||
    $instance = $local_action_manager->createInstance('entity.menu.add_link_form');
 | 
			
		||||
    $this->assertInstanceOf(LocalActionWithDestination::class, $instance);
 | 
			
		||||
 | 
			
		||||
    $deprecated_definition = $local_action_manager->getDefinition('entity.menu.add_link_form_deprecated');
 | 
			
		||||
    $this->assertSame(MenuLinkAdd::class, $deprecated_definition['class']);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,64 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Kernel;
 | 
			
		||||
 | 
			
		||||
use Drupal\KernelTests\KernelTestBase;
 | 
			
		||||
use Drupal\node\Entity\NodeType;
 | 
			
		||||
use Drupal\system\Entity\Menu;
 | 
			
		||||
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests menu settings when creating and editing content types.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MenuUiNodeTypeTest extends KernelTestBase {
 | 
			
		||||
 | 
			
		||||
  use ContentTypeCreationTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = [
 | 
			
		||||
    'field',
 | 
			
		||||
    'menu_ui',
 | 
			
		||||
    'node',
 | 
			
		||||
    'system',
 | 
			
		||||
    'text',
 | 
			
		||||
    'user',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Asserts that the available menu names are sorted alphabetically by label.
 | 
			
		||||
   *
 | 
			
		||||
   * @param \Drupal\node\Entity\NodeType $node_type
 | 
			
		||||
   *   The node type under test.
 | 
			
		||||
   */
 | 
			
		||||
  private function assertMenuNamesAreSorted(NodeType $node_type): void {
 | 
			
		||||
    // The available menus should be sorted by label, not machine name.
 | 
			
		||||
    $expected_options = [
 | 
			
		||||
      'b' => 'X',
 | 
			
		||||
      'c' => 'Y',
 | 
			
		||||
      'a' => 'Z',
 | 
			
		||||
    ];
 | 
			
		||||
    $form = $this->container->get('entity.form_builder')
 | 
			
		||||
      ->getForm($node_type, $node_type->isNew() ? 'add' : 'edit');
 | 
			
		||||
    $this->assertSame($expected_options, $form['menu']['menu_options']['#options']);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests node type-specific settings for Menu UI.
 | 
			
		||||
   */
 | 
			
		||||
  public function testContentTypeMenuSettings(): void {
 | 
			
		||||
    $this->installEntitySchema('node');
 | 
			
		||||
    $this->installConfig(['node']);
 | 
			
		||||
    Menu::create(['id' => 'a', 'label' => 'Z'])->save();
 | 
			
		||||
    Menu::create(['id' => 'b', 'label' => 'X'])->save();
 | 
			
		||||
    Menu::create(['id' => 'c', 'label' => 'Y'])->save();
 | 
			
		||||
    $this->assertMenuNamesAreSorted(NodeType::create());
 | 
			
		||||
    $this->assertMenuNamesAreSorted($this->createContentType());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,37 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Kernel\Migrate;
 | 
			
		||||
 | 
			
		||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests migration of menu_ui settings.
 | 
			
		||||
 *
 | 
			
		||||
 * @group menu_ui
 | 
			
		||||
 */
 | 
			
		||||
class MigrateMenuSettingsTest extends MigrateDrupal7TestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['menu_ui'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
    $this->installConfig(['menu_ui']);
 | 
			
		||||
    $this->executeMigration('menu_settings');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests migration of menu_ui settings.
 | 
			
		||||
   */
 | 
			
		||||
  public function testMigration(): void {
 | 
			
		||||
    $this->assertTrue(\Drupal::config('menu_ui.settings')->get('override_parent_selector'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										71
									
								
								web/core/modules/menu_ui/tests/src/Traits/MenuUiTrait.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								web/core/modules/menu_ui/tests/src/Traits/MenuUiTrait.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\menu_ui\Traits;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provides common methods for Menu UI module tests.
 | 
			
		||||
 */
 | 
			
		||||
trait MenuUiTrait {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Asserts that a menu fetched from the database matches an expected one.
 | 
			
		||||
   *
 | 
			
		||||
   * @param array $expected_item
 | 
			
		||||
   *   Array containing properties to check.
 | 
			
		||||
   * @param string $menu_plugin_id
 | 
			
		||||
   *   Menu item id.
 | 
			
		||||
   */
 | 
			
		||||
  protected function assertMenuLink(array $expected_item, $menu_plugin_id) {
 | 
			
		||||
    // Retrieve the menu link.
 | 
			
		||||
    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
 | 
			
		||||
    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
 | 
			
		||||
    $menu_link_manager->resetDefinitions();
 | 
			
		||||
    // Reset the static load cache.
 | 
			
		||||
    \Drupal::entityTypeManager()->getStorage('menu_link_content')->resetCache();
 | 
			
		||||
    $definition = $menu_link_manager->getDefinition($menu_plugin_id);
 | 
			
		||||
 | 
			
		||||
    $entity = NULL;
 | 
			
		||||
 | 
			
		||||
    // Pull the path from the menu link content.
 | 
			
		||||
    if (str_starts_with($menu_plugin_id, 'menu_link_content')) {
 | 
			
		||||
      [, $uuid] = explode(':', $menu_plugin_id, 2);
 | 
			
		||||
      /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $entity */
 | 
			
		||||
      $entity = \Drupal::service('entity.repository')
 | 
			
		||||
        ->loadEntityByUuid('menu_link_content', $uuid);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (isset($expected_item['children'])) {
 | 
			
		||||
      $child_ids = array_values($menu_link_manager->getChildIds($menu_plugin_id));
 | 
			
		||||
      sort($expected_item['children']);
 | 
			
		||||
      if ($child_ids) {
 | 
			
		||||
        sort($child_ids);
 | 
			
		||||
      }
 | 
			
		||||
      $this->assertSame($expected_item['children'], $child_ids);
 | 
			
		||||
      unset($expected_item['children']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (isset($expected_item['parents'])) {
 | 
			
		||||
      $parent_ids = array_values($menu_link_manager->getParentIds($menu_plugin_id));
 | 
			
		||||
      $this->assertSame($expected_item['parents'], $parent_ids);
 | 
			
		||||
      unset($expected_item['parents']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (isset($expected_item['langcode']) && $entity) {
 | 
			
		||||
      $this->assertEquals($expected_item['langcode'], $entity->langcode->value);
 | 
			
		||||
      unset($expected_item['langcode']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (isset($expected_item['enabled']) && $entity) {
 | 
			
		||||
      $this->assertEquals($expected_item['enabled'], $entity->enabled->value);
 | 
			
		||||
      unset($expected_item['enabled']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    foreach ($expected_item as $key => $value) {
 | 
			
		||||
      $this->assertNotNull($definition[$key]);
 | 
			
		||||
      $this->assertSame($value, $definition[$key]);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user