diff --git a/core/modules/menu_ui/src/Tests/MenuWebTestBase.php b/core/modules/menu_ui/src/Tests/MenuWebTestBase.php
index e0ee98fbf0..192063bbe5 100644
--- a/core/modules/menu_ui/src/Tests/MenuWebTestBase.php
+++ b/core/modules/menu_ui/src/Tests/MenuWebTestBase.php
@@ -2,13 +2,23 @@
 
 namespace Drupal\menu_ui\Tests;
 
+@trigger_error('The ' . __NAMESPACE__ . '\MenuWebTestBase is deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.0. Use the \Drupal\Tests\BrowserTestBase base class and the \Drupal\Tests\menu_ui\Traits\MenuUiTrait trait instead. See https://www.drupal.org/node/2870452.', E_USER_DEPRECATED);
+
 use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\menu_ui\Traits\MenuUiTrait;
 
 /**
  * Base class for menu web tests.
+ *
+ * @deprecated in Drupal 8.5.x, will be removed before Drupal 9.0.x. Use
+ *   \Drupal\Tests\menu_ui\Traits\MenuUiTrait methods, instead.
  */
 abstract class MenuWebTestBase extends WebTestBase {
 
+  use MenuUiTrait {
+    assertMenuLink as phpUnitAssertMenuLink;
+  }
+
   /**
    * Modules to enable.
    *
@@ -25,53 +35,9 @@
    *   Array containing properties to verify.
    */
   public function assertMenuLink($menu_plugin_id, array $expected_item) {
-    // Retrieve 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::entityManager()->getStorage('menu_link_content')->resetCache();
-    $definition = $menu_link_manager->getDefinition($menu_plugin_id);
-
-    $entity = NULL;
-
-    // Pull the path from the menu link content.
-    if (strpos($menu_plugin_id, 'menu_link_content') === 0) {
-      list(, $uuid) = explode(':', $menu_plugin_id, 2);
-      /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $entity */
-      $entity = \Drupal::entityManager()->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->assertEqual($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->assertEqual($expected_item['parents'], $parent_ids);
-      unset($expected_item['parents']);
-    }
-
-    if (isset($expected_item['langcode']) && $entity) {
-      $this->assertEqual($entity->langcode->value, $expected_item['langcode']);
-      unset($expected_item['langcode']);
-    }
-
-    if (isset($expected_item['enabled']) && $entity) {
-      $this->assertEqual($entity->enabled->value, $expected_item['enabled']);
-      unset($expected_item['enabled']);
-    }
-
-    foreach ($expected_item as $key => $value) {
-      $this->assertTrue(isset($definition[$key]));
-      $this->assertEqual($definition[$key], $value);
-    }
+    // In the PHPUnit method, the parameters were swapped because the
+    // expectation should go first.
+    $this->phpUnitAssertMenuLink($expected_item, $menu_plugin_id);
   }
 
 }
diff --git a/core/modules/menu_ui/src/Tests/MenuLanguageTest.php b/core/modules/menu_ui/tests/src/Functional/MenuUiLanguageTest.php
similarity index 90%
rename from core/modules/menu_ui/src/Tests/MenuLanguageTest.php
rename to core/modules/menu_ui/tests/src/Functional/MenuUiLanguageTest.php
index 4c48f05da7..ee9374141b 100644
--- a/core/modules/menu_ui/src/Tests/MenuLanguageTest.php
+++ b/core/modules/menu_ui/tests/src/Functional/MenuUiLanguageTest.php
@@ -1,10 +1,12 @@
 <?php
 
-namespace Drupal\menu_ui\Tests;
+namespace Drupal\Tests\menu_ui\Functional;
 
 use Drupal\Component\Utility\Unicode;
 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.
@@ -14,14 +16,20 @@
  *
  * @group menu_ui
  */
-class MenuLanguageTest extends MenuWebTestBase {
+class MenuUiLanguageTest extends BrowserTestBase {
+
+  use MenuUiTrait;
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = ['language'];
+  protected static $modules = [
+    'language',
+    'menu_link_content',
+    'menu_ui',
+  ];
 
   protected function setUp() {
     parent::setUp();
@@ -73,11 +81,11 @@ public function testMenuLanguage() {
     // Check the link was added with the correct menu link default language.
     $menu_links = entity_load_multiple_by_properties('menu_link_content', ['title' => $link_title]);
     $menu_link = reset($menu_links);
-    $this->assertMenuLink($menu_link->getPluginId(), [
+    $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')
@@ -95,22 +103,22 @@ public function testMenuLanguage() {
     // Check the link was added with the correct new menu link default language.
     $menu_links = entity_load_multiple_by_properties('menu_link_content', ['title' => $link_title]);
     $menu_link = reset($menu_links);
-    $this->assertMenuLink($menu_link->getPluginId(), [
+    $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->drupalPostForm('admin/structure/menu/item/' . $menu_link->id() . '/edit', $edit, t('Save'));
-    $this->assertMenuLink($menu_link->getPluginId(), [
+    $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
diff --git a/core/modules/menu_ui/src/Tests/MenuNodeTest.php b/core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php
similarity index 98%
rename from core/modules/menu_ui/src/Tests/MenuNodeTest.php
rename to core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php
index 99900955fb..7e22bcb46d 100644
--- a/core/modules/menu_ui/src/Tests/MenuNodeTest.php
+++ b/core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php
@@ -1,18 +1,18 @@
 <?php
 
-namespace Drupal\menu_ui\Tests;
+namespace Drupal\Tests\menu_ui\Functional;
 
-use Drupal\simpletest\WebTestBase;
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\menu_link_content\Entity\MenuLinkContent;
 use Drupal\node\Entity\Node;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Add, edit, and delete a node with menu link.
  *
  * @group menu_ui
  */
-class MenuNodeTest extends WebTestBase {
+class MenuUiNodeTest extends BrowserTestBase {
 
   /**
    * An editor user.
@@ -60,7 +60,7 @@ public function testMenuNodeFormWidget() {
     // 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->assertCacheContext('user.roles:authenticated');
+    $this->assertSession()->responseHeaderContains('X-Drupal-Cache-Contexts', 'user.roles:authenticated');
 
     // Verify that the menu link title has the correct maxlength.
     $max_length = \Drupal::entityManager()->getBaseFieldDefinitions('menu_link_content')['title']->getSetting('max_length');
diff --git a/core/modules/menu_ui/src/Tests/MenuTest.php b/core/modules/menu_ui/tests/src/Functional/MenuUiTest.php
similarity index 89%
rename from core/modules/menu_ui/src/Tests/MenuTest.php
rename to core/modules/menu_ui/tests/src/Functional/MenuUiTest.php
index dde95027bd..c03fb2f275 100644
--- a/core/modules/menu_ui/src/Tests/MenuTest.php
+++ b/core/modules/menu_ui/tests/src/Functional/MenuUiTest.php
@@ -1,16 +1,18 @@
 <?php
 
-namespace Drupal\menu_ui\Tests;
+namespace Drupal\Tests\menu_ui\Functional;
 
 use Drupal\block\Entity\Block;
-use Drupal\Component\Serialization\Json;
 use Drupal\Component\Utility\Unicode;
+use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
 use Drupal\Core\Menu\MenuLinkInterface;
 use Drupal\Core\Url;
 use Drupal\menu_link_content\Entity\MenuLinkContent;
 use Drupal\system\Entity\Menu;
 use Drupal\node\Entity\Node;
 use Drupal\node\NodeInterface;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\menu_ui\Traits\MenuUiTrait;
 
 /**
  * Add a custom menu, add menu links to the custom menu and Tools menu, check
@@ -18,14 +20,25 @@
  *
  * @group menu_ui
  */
-class MenuTest extends MenuWebTestBase {
+class MenuUiTest extends BrowserTestBase {
+
+  use MenuUiTrait;
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = ['node', 'block', 'contextual', 'help', 'path', 'test_page_test'];
+  protected static $modules = [
+    'block',
+    'contextual',
+    'help',
+    'menu_link_content',
+    'menu_ui',
+    'node',
+    'path',
+    'test_page_test',
+  ];
 
   /**
    * A user with administration rights.
@@ -216,7 +229,7 @@ public function addCustomMenu() {
 
     // Confirm that the custom menu block is available.
     $this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
-    $this->clickLinkPartialName('Place block');
+    $this->clickLink('Place block');
     $this->assertText($label);
 
     // Enable the block.
@@ -310,25 +323,25 @@ public function doMenuTests() {
     // -- item2
     // --- item3
 
-    $this->assertMenuLink($item1->getPluginId(), [
+    $this->assertMenuLink([
       'children' => [$item2->getPluginId(), $item3->getPluginId()],
       'parents' => [$item1->getPluginId()],
       // We assert the language code here to make sure that the language
       // selection element degrades gracefully without the Language module.
       'langcode' => 'en',
-    ]);
-    $this->assertMenuLink($item2->getPluginId(), [
+    ], $item1->getPluginId());
+    $this->assertMenuLink([
       'children' => [$item3->getPluginId()],
       'parents' => [$item2->getPluginId(), $item1->getPluginId()],
       // See above.
       'langcode' => 'en',
-    ]);
-    $this->assertMenuLink($item3->getPluginId(), [
+    ], $item2->getPluginId());
+    $this->assertMenuLink([
       'children' => [],
       'parents' => [$item3->getPluginId(), $item2->getPluginId(), $item1->getPluginId()],
       // See above.
       'langcode' => 'en',
-    ]);
+    ], $item3->getPluginId());
 
     // Verify menu links.
     $this->verifyMenuLink($item1, $node1);
@@ -350,18 +363,18 @@ public function doMenuTests() {
     // -- item5
     // -- item6
 
-    $this->assertMenuLink($item4->getPluginId(), [
+    $this->assertMenuLink([
       'children' => [$item5->getPluginId(), $item6->getPluginId()],
       'parents' => [$item4->getPluginId()],
       // See above.
       'langcode' => 'en',
-    ]);
-    $this->assertMenuLink($item5->getPluginId(), [
+    ], $item4->getPluginId());
+    $this->assertMenuLink([
       'children' => [],
       'parents' => [$item5->getPluginId(), $item4->getPluginId()],
       'langcode' => 'en',
-    ]);
-    $this->assertMenuLink($item6->getPluginId(), [
+    ], $item5->getPluginId());
+    $this->assertMenuLink([
       'children' => [],
       'parents' => [$item6->getPluginId(), $item4->getPluginId()],
       'route_name' => 'entity.node.canonical',
@@ -369,7 +382,7 @@ public function doMenuTests() {
       'url' => '',
       // See above.
       'langcode' => 'en',
-    ]);
+    ], $item6->getPluginId());
 
     // Modify menu links.
     $this->modifyMenuLink($item1);
@@ -390,37 +403,37 @@ public function doMenuTests() {
     // ---- item3
     // -- item6
 
-    $this->assertMenuLink($item1->getPluginId(), [
+    $this->assertMenuLink([
       'children' => [],
       'parents' => [$item1->getPluginId()],
       // See above.
       'langcode' => 'en',
-    ]);
-    $this->assertMenuLink($item4->getPluginId(), [
+    ], $item1->getPluginId());
+    $this->assertMenuLink([
       'children' => [$item5->getPluginId(), $item6->getPluginId(), $item2->getPluginId(), $item3->getPluginId()],
       'parents' => [$item4->getPluginId()],
       // See above.
       'langcode' => 'en',
-    ]);
+    ], $item4->getPluginId());
 
-    $this->assertMenuLink($item5->getPluginId(), [
+    $this->assertMenuLink([
       'children' => [$item2->getPluginId(), $item3->getPluginId()],
       'parents' => [$item5->getPluginId(), $item4->getPluginId()],
       // See above.
       'langcode' => 'en',
-    ]);
-    $this->assertMenuLink($item2->getPluginId(), [
+    ], $item5->getPluginId());
+    $this->assertMenuLink([
       'children' => [$item3->getPluginId()],
       'parents' => [$item2->getPluginId(), $item5->getPluginId(), $item4->getPluginId()],
       // See above.
       'langcode' => 'en',
-    ]);
-    $this->assertMenuLink($item3->getPluginId(), [
+    ], $item2->getPluginId());
+    $this->assertMenuLink([
       'children' => [],
       'parents' => [$item3->getPluginId(), $item2->getPluginId(), $item5->getPluginId(), $item4->getPluginId()],
       // See above.
       'langcode' => 'en',
-    ]);
+    ], $item3->getPluginId());
 
     // Add 102 menu links with increasing weights, then make sure the last-added
     // item's weight doesn't get changed because of the old hardcoded delta=50.
@@ -428,7 +441,7 @@ public function doMenuTests() {
     for ($i = -50; $i <= 51; $i++) {
       $items[$i] = $this->addMenuLink('', '/node/' . $node1->id(), $menu_name, TRUE, strval($i));
     }
-    $this->assertMenuLink($items[51]->getPluginId(), ['weight' => '51']);
+    $this->assertMenuLink(['weight' => '51'], $items[51]->getPluginId());
 
     // Disable a link and then re-enable the link via the overview form.
     $this->disableMenuLink($item1);
@@ -446,15 +459,15 @@ public function doMenuTests() {
     $item5->save();
 
     // Verify in the database.
-    $this->assertMenuLink($item1->getPluginId(), ['enabled' => 1]);
+    $this->assertMenuLink(['enabled' => 1], $item1->getPluginId());
 
     // Add an external link.
     $item7 = $this->addMenuLink('', 'https://www.drupal.org', $menu_name);
-    $this->assertMenuLink($item7->getPluginId(), ['url' => 'https://www.drupal.org']);
+    $this->assertMenuLink(['url' => 'https://www.drupal.org'], $item7->getPluginId());
 
     // Add <front> menu item.
     $item8 = $this->addMenuLink('', '/', $menu_name);
-    $this->assertMenuLink($item8->getPluginId(), ['route_name' => '<front>']);
+    $this->assertMenuLink(['route_name' => '<front>'], $item8->getPluginId());
     $this->drupalGet('');
     $this->assertResponse(200);
     // Make sure we get routed correctly.
@@ -531,7 +544,7 @@ public function testSystemMenuRename() {
     // Make sure menu shows up with new name in block addition.
     $default_theme = $this->config('system.theme')->get('default');
     $this->drupalget('admin/structure/block/list/' . $default_theme);
-    $this->clickLinkPartialName('Place block');
+    $this->clickLink('Place block');
     $this->assertText($edit['label']);
   }
 
@@ -557,30 +570,7 @@ public function testUnpublishedNodeMenuItem() {
     $this->assertNoText($item->getTitle(), "Menu link pointing to unpublished node is only visible to users with 'bypass node access' permission");
     // The cache contexts associated with the (in)accessible menu links are
     // bubbled. See DefaultMenuLinkTreeManipulators::menuLinkCheckAccess().
-    $this->assertCacheContext('user.permissions');
-  }
-
-  /**
-   * Tests the contextual links on a menu block.
-   */
-  public function testBlockContextualLinks() {
-    $this->drupalLogin($this->drupalCreateUser(['administer menu', 'access contextual links', 'administer blocks']));
-    $custom_menu = $this->addCustomMenu();
-    $this->addMenuLink('', '/', $custom_menu->id());
-    $block = $this->drupalPlaceBlock('system_menu_block:' . $custom_menu->id(), ['label' => 'Custom menu', 'provider' => 'system']);
-    $this->drupalGet('test-page');
-
-    $id = 'block:block=' . $block->id() . ':langcode=en|menu:menu=' . $custom_menu->id() . ':langcode=en';
-    // @see \Drupal\contextual\Tests\ContextualDynamicContextTest:assertContextualLinkPlaceHolder()
-    $this->assertRaw('<div data-contextual-id="' . $id . '"></div>', format_string('Contextual link placeholder with id @id exists.', ['@id' => $id]));
-
-    // Get server-rendered contextual links.
-    // @see \Drupal\contextual\Tests\ContextualDynamicContextTest:renderContextualLinks()
-    $post = ['ids[0]' => $id];
-    $response = $this->drupalPost('contextual/render', 'application/json', $post, ['query' => ['destination' => 'test-page']]);
-    $this->assertResponse(200);
-    $json = Json::decode($response);
-    $this->assertIdentical($json[$id], '<ul class="contextual-links"><li class="block-configure"><a href="' . base_path() . 'admin/structure/block/manage/' . $block->id() . '">Configure block</a></li><li class="entitymenuedit-form"><a href="' . base_path() . 'admin/structure/menu/manage/' . $custom_menu->id() . '">Edit menu</a></li></ul>');
+    $this->assertSession()->responseHeaderContains('X-Drupal-Cache-Contexts', 'user.permissions');
   }
 
   /**
@@ -627,7 +617,7 @@ public function addMenuLink($parent = '', $path = '/', $menu_name = 'tools', $ex
 
     $menu_link = reset($menu_links);
     $this->assertTrue($menu_link, 'Menu link was found in database.');
-    $this->assertMenuLink($menu_link->getPluginId(), ['menu_name' => $menu_name, 'children' => [], 'parent' => $parent]);
+    $this->assertMenuLink(['menu_name' => $menu_name, 'children' => [], 'parent' => $parent], $menu_link->getPluginId());
 
     return $menu_link;
   }
@@ -841,7 +831,7 @@ public function disableMenuLink(MenuLinkContent $item) {
 
     // Unlike most other modules, there is no confirmation message displayed.
     // Verify in the database.
-    $this->assertMenuLink($item->getPluginId(), ['enabled' => 0]);
+    $this->assertMenuLink(['enabled' => 0], $item->getPluginId());
   }
 
   /**
@@ -856,25 +846,7 @@ public function enableMenuLink(MenuLinkContent $item) {
     $this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
 
     // Verify in the database.
-    $this->assertMenuLink($item->getPluginId(), ['enabled' => 1]);
-  }
-
-  /**
-   * Tests if administrative users other than user 1 can access the menu parents
-   * AJAX callback.
-   */
-  public function testMenuParentsJsAccess() {
-    $admin = $this->drupalCreateUser(['administer menu']);
-    $this->drupalLogin($admin);
-    // Just check access to the callback overall, the POST data is irrelevant.
-    $this->drupalGetAjax('admin/structure/menu/parents');
-    $this->assertResponse(200);
-
-    // Do standard user tests.
-    // Log in the user.
-    $this->drupalLogin($this->authenticatedUser);
-    $this->drupalGetAjax('admin/structure/menu/parents');
-    $this->assertResponse(403);
+    $this->assertMenuLink(['enabled' => 1], $item->getPluginId());
   }
 
   /**
@@ -939,6 +911,22 @@ private function verifyAccess($response = 200) {
   }
 
   /**
+   * Tests if admin users, other than UID1, can access parents AJAX callback.
+   */
+  public function testMenuParentsJsAccess() {
+    $this->drupalLogin($this->drupalCreateUser(['administer menu']));
+    // Just check access to the callback overall, the POST data is irrelevant.
+    $this->drupalGet('admin/structure/menu/parents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']], ['X-Requested-With: XMLHttpRequest']);
+    $this->assertSession()->statusCodeEquals(200);
+
+    // Log in as authenticated user.
+    $this->drupalLogin($this->drupalCreateUser());
+    // Check that a simple user is not able to access the menu.
+    $this->drupalGet('admin/structure/menu/parents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']], ['X-Requested-With: XMLHttpRequest']);
+    $this->assertSession()->statusCodeEquals(403);
+  }
+
+  /**
    * Tests menu block settings.
    */
   protected function doTestMenuBlock() {
diff --git a/core/modules/menu_ui/tests/src/FunctionalJavascript/MenuUiJavascriptTest.php b/core/modules/menu_ui/tests/src/FunctionalJavascript/MenuUiJavascriptTest.php
new file mode 100644
index 0000000000..d817c8a41f
--- /dev/null
+++ b/core/modules/menu_ui/tests/src/FunctionalJavascript/MenuUiJavascriptTest.php
@@ -0,0 +1,159 @@
+<?php
+
+namespace Drupal\Tests\menu_ui\FunctionalJavascript;
+
+use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+use Drupal\system\Entity\Menu;
+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 JavascriptTestBase {
+
+  use ContextualLinkClickTrait;
+  use MenuUiTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'block',
+    'contextual',
+    'menu_link_content',
+    'menu_ui',
+    'test_page_test'
+  ];
+
+  /**
+   * Tests the contextual links on a menu block.
+   */
+  public function testBlockContextualLinks() {
+    $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');
+    // Wait for contextual link AJAX request to alter the DOM.
+    $this->assertSession()->assertWaitOnAjaxRequest();
+
+    // Click on 'Configure block' contextual link.
+    $this->clickContextualLink("#block-{$block->id()}", 'Configure block');
+    // Check that we're on block configuration form.
+    $this->getSession()->getPage()->findLink('Remove block');
+
+    $this->drupalGet('test-page');
+    // Wait for contextual link AJAX request to alter the DOM.
+    $this->assertSession()->assertWaitOnAjaxRequest();
+
+    // Click on 'Configure block' 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 = strtolower($this->randomMachineName(MENU_MAX_MENU_NAME_LENGTH_UI + 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, MENU_MAX_MENU_NAME_LENGTH_UI));
+    $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");
+    $this->assertSession()->statusCodeEquals(200);
+
+    $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->drupalPostForm(NULL, $edit, 'Save');
+    $this->assertSession()->statusCodeEquals(200);
+    $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;
+  }
+
+}
diff --git a/core/modules/menu_ui/src/Tests/MenuWebTestBase.php b/core/modules/menu_ui/tests/src/Traits/MenuUiTrait.php
similarity index 57%
copy from core/modules/menu_ui/src/Tests/MenuWebTestBase.php
copy to core/modules/menu_ui/tests/src/Traits/MenuUiTrait.php
index e0ee98fbf0..c471823510 100644
--- a/core/modules/menu_ui/src/Tests/MenuWebTestBase.php
+++ b/core/modules/menu_ui/tests/src/Traits/MenuUiTrait.php
@@ -1,36 +1,27 @@
 <?php
 
-namespace Drupal\menu_ui\Tests;
-
-use Drupal\simpletest\WebTestBase;
+namespace Drupal\Tests\menu_ui\Traits;
 
 /**
- * Base class for menu web tests.
+ * Provides common methods for Menu UI module tests.
  */
-abstract class MenuWebTestBase extends WebTestBase {
+trait MenuUiTrait {
 
   /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['menu_ui', 'menu_link_content'];
-
-  /**
-   * Fetches the menu item from the database and compares it to expected item.
+   * Asserts that a menu fetched from the database matches an expected one.
    *
+   * @param array $expected_item
+   *   Array containing properties to check.
    * @param int $menu_plugin_id
    *   Menu item id.
-   * @param array $expected_item
-   *   Array containing properties to verify.
    */
-  public function assertMenuLink($menu_plugin_id, array $expected_item) {
-    // Retrieve menu link.
+  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::entityManager()->getStorage('menu_link_content')->resetCache();
+    \Drupal::entityTypeManager()->getStorage('menu_link_content')->resetCache();
     $definition = $menu_link_manager->getDefinition($menu_plugin_id);
 
     $entity = NULL;
@@ -39,7 +30,8 @@ public function assertMenuLink($menu_plugin_id, array $expected_item) {
     if (strpos($menu_plugin_id, 'menu_link_content') === 0) {
       list(, $uuid) = explode(':', $menu_plugin_id, 2);
       /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $entity */
-      $entity = \Drupal::entityManager()->loadEntityByUuid('menu_link_content', $uuid);
+      $entity = \Drupal::service('entity.repository')
+        ->loadEntityByUuid('menu_link_content', $uuid);
     }
 
     if (isset($expected_item['children'])) {
@@ -48,29 +40,29 @@ public function assertMenuLink($menu_plugin_id, array $expected_item) {
       if ($child_ids) {
         sort($child_ids);
       }
-      $this->assertEqual($expected_item['children'], $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->assertEqual($expected_item['parents'], $parent_ids);
+      $this->assertSame($expected_item['parents'], $parent_ids);
       unset($expected_item['parents']);
     }
 
     if (isset($expected_item['langcode']) && $entity) {
-      $this->assertEqual($entity->langcode->value, $expected_item['langcode']);
+      $this->assertEquals($expected_item['langcode'], $entity->langcode->value);
       unset($expected_item['langcode']);
     }
 
     if (isset($expected_item['enabled']) && $entity) {
-      $this->assertEqual($entity->enabled->value, $expected_item['enabled']);
+      $this->assertEquals($expected_item['enabled'], $entity->enabled->value);
       unset($expected_item['enabled']);
     }
 
     foreach ($expected_item as $key => $value) {
-      $this->assertTrue(isset($definition[$key]));
-      $this->assertEqual($definition[$key], $value);
+      $this->assertNotNull($definition[$key]);
+      $this->assertSame($value, $definition[$key]);
     }
   }
 
