diff --git a/src/Tests/FlagTestBase.php b/src/Tests/FlagTestBase.php
index eb04e9b..8433cf7 100644
--- a/src/Tests/FlagTestBase.php
+++ b/src/Tests/FlagTestBase.php
@@ -7,6 +7,7 @@ use Drupal\simpletest\WebTestBase;
 use Drupal\flag\Entity\Flag;
 use Drupal\Core\Template\Attribute;
 use Drupal\flag\Tests\FlagWithFormTrait;
+use Drupal\Tests\flag\Traits\FlagPermissionTrait;
 
 /**
  * Provides common methods for Flag tests.
diff --git a/tests/src/Functional/FlagContextualLinksTest.php b/tests/src/FunctionalJavascript/FlagContextualLinksTest.php
similarity index 68%
rename from tests/src/Functional/FlagContextualLinksTest.php
rename to tests/src/FunctionalJavascript/FlagContextualLinksTest.php
index f19e0b1..470a0bd 100644
--- a/tests/src/Functional/FlagContextualLinksTest.php
+++ b/tests/src/FunctionalJavascript/FlagContextualLinksTest.php
@@ -1,30 +1,40 @@
 <?php
 
-namespace Drupal\Tests\flag\Functional;
+namespace Drupal\Tests\flag\FunctionalJavascript;
 
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Component\Serialization\Json;
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Url;
-use Drupal\node\NodeInterface;
 use Drupal\flag\FlagInterface;
-use Drupal\flag\Tests\FlagWithFormTrait;
+use Drupal\Tests\flag\Traits\FlagWithFormTrait;
+use Drupal\Tests\flag\Traits\FlagPermissionsTrait;
 use Drupal\flag\Tests\FlagCreateTrait;
-use Drupal\Tests\BrowserTestBase;
+use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+use Drupal\node\NodeInterface;
 
 /**
  * Test the contextual links with Reload link type.
  *
  * @group flag
  */
-class FlagContextualLinksTest extends BrowserTestBase {
+class FlagContextualLinksTest extends JavascriptTestBase {
 
   use FlagWithFormTrait;
   use FlagCreateTrait;
+  use FlagPermissionsTrait;
+
   /**
    * {@inheritdoc}
    */
-  public static $modules = [ 'contextual', 'field_ui', 'flag', 'node', 'system', 'user'];
+  public static $modules = [
+    'contextual',
+    'field_ui',
+    'flag',
+    'node',
+    'system',
+    'user',
+  ];
 
   /**
    * The flag.
@@ -41,7 +51,7 @@ class FlagContextualLinksTest extends BrowserTestBase {
   protected $adminUser;
 
   /**
-   * * An authenticated user to test flagging.
+   * An authenticated user to test flagging.
    *
    * @var \Drupal\user\Entity\User|false
    */
@@ -54,6 +64,9 @@ class FlagContextualLinksTest extends BrowserTestBase {
    */
   protected $nodeType = 'article';
 
+  /**
+   * {@inheritdoc}
+   */
   public function setUp() {
     parent::setUp();
 
@@ -78,7 +91,7 @@ class FlagContextualLinksTest extends BrowserTestBase {
   }
 
   /**
-   * Create a new flag with the Reload link type and enable contextual links display.
+   * Create a flag with a Reload link type and enable contextual links display.
    */
   public function testNodeLinks() {
     $this->doCreateFlag();
@@ -115,22 +128,24 @@ class FlagContextualLinksTest extends BrowserTestBase {
     // Open node view page that renders Full view mode.
     $this->drupalGet('node/' . $node->id());
 
-    // Expect Contextual links id for this node to contain flag_keys metadata.
+    // Expect the contextual links identifer for this node to contain flag_keys
+    // metadata related to the flag action.
     $contextual_links_id = 'node:node=' . $node->id() . ':changed=' . $node->getChangedTime() . '&flag_keys=' . $this->flag->id() . '-flag&langcode=en';
     $this->assertContextualLinkPlaceHolder($contextual_links_id);
 
     $flag_action_url = $this->getFlagContextualLinkUrl($this->flag, $node, $contextual_links_id, 'flag');
-    $this->assertTrue($flag_action_url, "Flag link found in contextual links.");
+    $this->assertTrue($flag_action_url, 'Flag link found in contextual links.');
 
     // Emulate click on flag link in Contextual links.
     $this->drupalGet($flag_action_url);
 
-    // Expect Contextual links id for this node to contain flag_keys metadata with unflag action.
+    // Expect the contextual links identifier for this node to contain flag_keys
+    // metadata related to the unflag action.
     $contextual_links_id = 'node:node=' . $node->id() . ':changed=' . $node->getChangedTime() . '&flag_keys=' . $this->flag->id() . '-unflag&langcode=en';
     $this->assertContextualLinkPlaceHolder($contextual_links_id);
 
-    $flag_action_url = $this->getFlagContextualLinkUrl($this->flag, $node, $contextual_links_id, 'unflag');
-    $this->assertTrue($flag_action_url, "Unflag link found in contextual links.");
+    $unflag_action_url = $this->getFlagContextualLinkUrl($this->flag, $node, $contextual_links_id, 'unflag');
+    $this->assertTrue($unflag_action_url, 'Unflag link found in contextual links.');
 
     // Login as normal user.
     $this->drupalLogin($this->drupalCreateUser());
@@ -138,40 +153,52 @@ class FlagContextualLinksTest extends BrowserTestBase {
     // Open node view page that renders Full view mode.
     $this->drupalGet('node/' . $node->id());
 
-    // Expect Contextual links id for this node to contain flag_keys metadata.
+    // Expect the contextual links identifier for this node to contain flag_keys
+    // metadata related to the flag action.
     $contextual_links_id = 'node:node=' . $node->id() . ':changed=' . $node->getChangedTime() . '&flag_keys=' . $this->flag->id() . '-flag&langcode=en';
     $this->assertContextualLinkPlaceHolder($contextual_links_id);
 
-    $flag_action_url = $this->getFlagContextualLinkUrl($this->flag, $node, $contextual_links_id, 'flag');
-    $this->assertTrue($flag_action_url, "Flag link found in contextual links.");
+    $flag_action_url2 = $this->getFlagContextualLinkUrl($this->flag, $node, $contextual_links_id, 'flag');
+    $this->assertTrue($flag_action_url2, 'Flag link found in contextual links.');
   }
 
   /**
-   * Get server-rendered contextual links for the given contextual link ids.
+   * Get server-rendered contextual links.
+   *
+   * The response is based on a given list of contextual link identifiers.
    *
-   * @see \Drupal\contextual\Tests\ContextualDynamicContextTest::renderContextualLinks().
    * @param array $ids
-   *   An array of contextual link ids.
+   *   An array of contextual link identifiers.
    * @param string $current_path
    *   The Drupal path for the page for which the contextual links are rendered.
    *
    * @return string
    *   The response body.
+   *
+   * @see \Drupal\contextual\Tests\ContextualDynamicContextTest::renderContextualLinks()
    */
-  protected function renderContextualLinks($ids, $current_path) {
-    $post = array();
+  protected function renderContextualLinks(array $ids, $current_path) {
+    $post = [];
     for ($i = 0; $i < count($ids); $i++) {
       $post['ids[' . $i . ']'] = $ids[$i];
     }
-    return $this->drupalPostWithFormat('contextual/render', 'json', $post, array('query' => array('destination' => $current_path)));
+    return $this->drupalPostWithFormat('contextual/render', 'json', $post, ['query' => ['destination' => $current_path]]);
   }
 
   /**
-   * Helper method that returns a flag action URL from contextual links markup
-   * by contextual links id.
+   * Returns a flag action contextual link in the form of a URL.
    *
+   * A contextual identifier is needed to fully specify the final markup.
+   *
+   * @param \Drupal\flag\FlagInterface $flag
+   *   The flag associated with the contextual link.
+   * @param Drupal\node\NodeInterface $node
+   *   The node associated with the contextual link.
    * @param string $contextual_links_id
-   *   Contextual links placeholder ids string.
+   *   Contextual links placeholder identifier string.
+   * @param string $flag_action
+   *   Either 'flag' or 'unflag' to reflect the action required.
+   *
    * @return \Drupal\Core\Url|FALSE
    *   Returns either a flag action URL object or FALSE in case that flag link
    *   wasn't found in the contextual links markup.
@@ -184,15 +211,15 @@ class FlagContextualLinksTest extends BrowserTestBase {
     $response = $this->renderContextualLinks([$contextual_links_id], 'node');
     $this->assertResponse(200);
     $json = Json::decode($response);
-    $flag_url = Url::fromRoute("flag.action_link_{$flag_action}", array(
+    $flag_url = Url::fromRoute("flag.action_link_{$flag_action}", [
       'flag' => $flag->id(),
       'entity_id' => $node->id(),
-    ));
+    ]);
 
     $flag_short_text = $flag->getShortText($flag_action);
 
-    $matches = array();
-    $url_pattern =  preg_quote(base_path()) . '(' . preg_quote($flag_url->getInternalPath(), '@') . '[^"]*)';
+    $matches = [];
+    $url_pattern = preg_quote(base_path()) . '(' . preg_quote($flag_url->getInternalPath(), '@') . '[^"]*)';
     $found = preg_match('@' . preg_quote('<ul class="contextual-links"><li class="flag-test-label-123"><a href="') .
       $url_pattern . preg_quote('">' . Html::escape($flag_short_text) . '</a></li></ul>', '@') . '@',
       $json[$contextual_links_id], $matches);
diff --git a/tests/src/FunctionalJavascript/ModalFormTest.php b/tests/src/FunctionalJavascript/ModalFormTest.php
index 363b352..8d99b6f 100644
--- a/tests/src/FunctionalJavascript/ModalFormTest.php
+++ b/tests/src/FunctionalJavascript/ModalFormTest.php
@@ -85,6 +85,15 @@ class ModalFormTest extends JavascriptTestBase {
     $this->drupalGet($this->node->toUrl());
     $this->clickLink($this->flag->getShortText('flag'));
 
+    $this->getSession
+       $radioButton = $ctx->getSession()->getPage()->find('css', "#$radioId");
+    if (!$radioButton) {
+        throw new \Exception("$labelText radio button not found.");
+    }
+
+    $ctx->fillField($radioId, $radioButton->getAttribute('value'));
+
+
     // Should be on the confirm form page, since this isn't using a modal.
     $expected = Url::fromRoute('flag.confirm_flag', [
       'flag' => $this->flag->id(),
diff --git a/src/Tests/FlagPermissionsTrait.php b/tests/src/Traits/FlagPermissionsTrait.php
similarity index 97%
rename from src/Tests/FlagPermissionsTrait.php
rename to tests/src/Traits/FlagPermissionsTrait.php
index aec7853..a8206e7 100644
--- a/src/Tests/FlagPermissionsTrait.php
+++ b/tests/src/Traits/FlagPermissionsTrait.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\flag\Tests;
+namespace Drupal\Tests\flag\Traits;
 
 use Drupal\user\Entity\Role;
 use Drupal\user\RoleInterface;
diff --git a/tests/src/Traits/FlagWithFormTrait.php b/tests/src/Traits/FlagWithFormTrait.php
new file mode 100644
index 0000000..f67d884
--- /dev/null
+++ b/tests/src/Traits/FlagWithFormTrait.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace Drupal\Tests\flag\Traits;
+
+use Drupal\flag\Entity\Flag;
+
+/**
+ * Trait for creating Flags using web pages.
+ */
+trait FlagWithFormTrait {
+
+    /**
+   * Creates a flag entity using the admin UI.
+   *
+   * If you do not provide any bundles in $edit, all bundles for $entity_type
+   * are assumed.
+   *
+   * @param string|null $entity_type
+   *   (optional) A string containing the flaggable entity type, by default
+   *   'node'.
+   * @param array $edit
+   *   (optional) An array of form field names and values. If omitted, random
+   *   strings will be used for the flag ID, label, short and long text.
+   * @param string|null $link_type
+   *   (optional) A string containing the link type ID. Is omitted, assumes
+   *   'reload'.
+   *
+   * @return \Drupal\flag\FlagInterface|null
+   *   The created flag entity.
+   */
+  protected function createFlagWithForm($entity_type = 'node', $edit = [], $link_type = 'reload') {
+    // Submit the flag add page.
+     // Verify default, non-modal behavior.
+    $this->drupalGet('admin/structure/flags/add');
+    $first_page = $this->getSession()->getPage();
+    // @todo Vary which radio button is pressed based on $entity_type.
+    $radio_input = $first_page->findField('flag_entity_type');
+    $radio_input->click();
+    $first_page->findButton('Continue')->click();
+
+    // Create an array of defaults.
+    $default_edit = [
+      'id' => strtolower($this->randomMachineName()),
+      'label' => $this->randomString(),
+      'flag_short' => $this->randomString(),
+      'unflag_short' => $this->randomString(),
+      'flag_long' => $this->randomString(16),
+      'unflag_long' => $this->randomString(16),
+      'flag_message' => $this->randomString(32),
+      'unflag_message' => $this->randomString(32),
+      'unflag_denied_text' => $this->randomString(),
+    ];
+
+    // Merge the default values with the edit array.
+    $final_edit = array_merge($default_edit, $edit);
+
+    // Submit the flag details form.
+    $this->drupalPostForm(NULL, $final_edit, 'Create Flag');
+
+    // Load the new flag we created.
+    $flag = Flag::load($final_edit['id']);
+
+    // Make sure that we actually did get a flag entity.
+    $this->assertTrue($flag instanceof Flag);
+
+    // Return the flag.
+    return $flag;
+  }
+
+}
