diff --git a/core/modules/content_translation/src/Tests/ContentTranslationContextualLinksTest.php b/core/modules/content_translation/tests/src/Functional/ContentTranslationContextualLinksTest.php
similarity index 64%
rename from core/modules/content_translation/src/Tests/ContentTranslationContextualLinksTest.php
rename to core/modules/content_translation/tests/src/Functional/ContentTranslationContextualLinksTest.php
index 080ffb9549..b85c3aad5d 100644
--- a/core/modules/content_translation/src/Tests/ContentTranslationContextualLinksTest.php
+++ b/core/modules/content_translation/tests/src/Functional/ContentTranslationContextualLinksTest.php
@@ -1,19 +1,18 @@
 <?php
 
-namespace Drupal\content_translation\Tests;
+namespace Drupal\Tests\content_translation\Functional;
 
-use Drupal\Component\Serialization\Json;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\simpletest\WebTestBase;
 use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests that contextual links are available for content translation.
  *
  * @group content_translation
  */
-class ContentTranslationContextualLinksTest extends WebTestBase {
+class ContentTranslationContextualLinksTest extends BrowserTestBase {
 
   /**
    * The bundle being tested.
@@ -118,60 +117,11 @@ public function testContentTranslationContextualLinks() {
     $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
     $this->drupalLogout();
 
-    // Check that the translate link appears on the node page.
+    // Check that the link leads to the translate page.
     $this->drupalLogin($this->translator);
     $translate_link = 'node/' . $node->id() . '/translations';
-
-    $response = $this->renderContextualLinks(['node:node=1:'], 'node/' . $node->id());
-    $this->assertResponse(200);
-    $json = Json::decode($response);
-    $this->setRawContent($json['node:node=1:']);
-    $this->assertLinkByHref($translate_link, 0, 'The contextual link to translate the node is shown.');
-
-    // Check that the link leads to the translate page.
     $this->drupalGet($translate_link);
     $this->assertRaw(t('Translations of %label', ['%label' => $node->label()]), 'The contextual link leads to the translate page.');
   }
 
-  /**
-   * Get server-rendered contextual links for the given contextual link ids.
-   *
-   * Copied from \Drupal\contextual\Tests\ContextualDynamicContextTest::renderContextualLinks().
-   *
-   * @param array $ids
-   *   An array of contextual link ids.
-   * @param string $current_path
-   *   The Drupal path for the page for which the contextual links are rendered.
-   *
-   * @return string
-   *   The response body.
-   */
-  protected function renderContextualLinks($ids, $current_path) {
-    // Build POST values.
-    $post = [];
-    for ($i = 0; $i < count($ids); $i++) {
-      $post['ids[' . $i . ']'] = $ids[$i];
-    }
-
-    // Serialize POST values.
-    foreach ($post as $key => $value) {
-      // Encode according to application/x-www-form-urlencoded
-      // Both names and values needs to be urlencoded, according to
-      // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
-      $post[$key] = urlencode($key) . '=' . urlencode($value);
-    }
-    $post = implode('&', $post);
-
-    // Perform HTTP request.
-    return $this->curlExec([
-      CURLOPT_URL => \Drupal::url('contextual.render', [], ['absolute' => TRUE, 'query' => ['destination' => $current_path]]),
-      CURLOPT_POST => TRUE,
-      CURLOPT_POSTFIELDS => $post,
-      CURLOPT_HTTPHEADER => [
-        'Accept: application/json',
-        'Content-Type: application/x-www-form-urlencoded',
-      ],
-    ]);
-  }
-
 }
diff --git a/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php b/core/modules/content_translation/tests/src/Functional/ContentTranslationWorkflowsTest.php
similarity index 98%
rename from core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php
rename to core/modules/content_translation/tests/src/Functional/ContentTranslationWorkflowsTest.php
index 66469ebb4f..759bd6dbba 100644
--- a/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php
+++ b/core/modules/content_translation/tests/src/Functional/ContentTranslationWorkflowsTest.php
@@ -1,10 +1,11 @@
 <?php
 
-namespace Drupal\content_translation\Tests;
+namespace Drupal\Tests\content_translation\Functional;
 
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Url;
+use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
 use Drupal\user\UserInterface;
 
 /**
@@ -14,6 +15,8 @@
  */
 class ContentTranslationWorkflowsTest extends ContentTranslationTestBase {
 
+  use AssertPageCacheContextsAndTagsTrait;
+
   /**
    * The entity used for testing.
    *
diff --git a/core/modules/content_translation/tests/src/FunctionalJavascript/ContentTranslationContextualLinksTest.php b/core/modules/content_translation/tests/src/FunctionalJavascript/ContentTranslationContextualLinksTest.php
new file mode 100644
index 0000000000..b095399195
--- /dev/null
+++ b/core/modules/content_translation/tests/src/FunctionalJavascript/ContentTranslationContextualLinksTest.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace Drupal\Tests\content_translation\FunctionalJavascript;
+
+use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+use Drupal\language\Entity\ConfigurableLanguage;
+
+/**
+ * Tests that contextual links are available for content translation.
+ *
+ * @group content_translation
+ */
+class ContentTranslationContextualLinksTest extends JavascriptTestBase {
+
+  /**
+   * The 'translator' user to use during testing.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $translator;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['content_translation', 'contextual', 'node'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Set up an additional language.
+    ConfigurableLanguage::createFromLangcode('es')->save();
+
+    // Create a content type.
+    $this->drupalCreateContentType(['type' => 'page']);
+
+    // Enable content translation.
+    $this->drupalLogin($this->rootUser);
+    $this->drupalGet('admin/config/regional/content-language');
+    $edit = [
+      'entity_types[node]' => TRUE,
+      'settings[node][page][translatable]' => TRUE,
+    ];
+    $this->drupalPostForm(NULL, $edit, t('Save configuration'));
+    $this->drupalLogout();
+
+    // Create a translator user.
+    $permissions = [
+      'access contextual links',
+      'administer nodes',
+      'edit any page content',
+      'translate any entity',
+    ];
+    $this->translator = $this->drupalCreateUser($permissions);
+  }
+
+  /**
+   * Tests that a contextual link is available for translating a node.
+   */
+  public function testContentTranslationContextualLinks() {
+    $node = $this->drupalCreateNode(['type' => 'page', 'title' => 'Test']);
+
+    // Check that the translate link appears on the node page.
+    $this->drupalLogin($this->translator);
+    $this->drupalGet('node/' . $node->id());
+    $link = $this->assertSession()->waitForElement('css', '[data-contextual-id^="node:node=1"] .contextual-links a:contains("Translate")');
+    $this->assertContains('node/1/translations', $link->getAttribute('href'));
+  }
+
+}
