diff --git a/core/tests/Drupal/FunctionalTests/AssertLegacyTrait.php b/core/tests/Drupal/FunctionalTests/AssertLegacyTrait.php
index d63ada6..33eea7f 100644
--- a/core/tests/Drupal/FunctionalTests/AssertLegacyTrait.php
+++ b/core/tests/Drupal/FunctionalTests/AssertLegacyTrait.php
@@ -124,7 +124,7 @@ protected function assertResponse($code) {
   protected function assertFieldByName($name, $value = NULL) {
     $this->assertSession()->fieldExists($name);
     if ($value !== NULL) {
-      $this->assertSession()->fieldValueEquals($name, $value);
+      $this->assertSession()->fieldValueEquals($name, (string) $value);
     }
   }
 
@@ -163,6 +163,21 @@ protected function assertRaw($raw) {
   }
 
   /**
+   * Passes if the raw text IS not found on the loaded page, fail otherwise.
+   *
+   * Raw text refers to the raw HTML that the page generated.
+   *
+   * @param string $raw
+   *   Raw (HTML) string to look for.
+   *
+   * @deprecated Scheduled for removal in Drupal 9.0.0.
+   *   Use $this->assertSession()->responseNotContains() instead.
+   */
+  protected function assertNoRaw($raw) {
+    $this->assertSession()->responseNotContains($raw);
+  }
+
+  /**
    * Pass if the page title is the given string.
    *
    * @param string $expected_title
@@ -181,12 +196,97 @@ protected function assertTitle($expected_title) {
    *   Text between the anchor tags.
    * @param int $index
    *   Link position counting from zero.
+   *
+   * @deprecated Scheduled for removal in Drupal 9.0.0.
+   *   Use $this->assertSession()->linkExists() instead.
    */
   protected function assertLink($label, $index = 0) {
     return $this->assertSession()->linkExists($label, $index);
   }
 
   /**
+   * Passes if a link with the specified label is not found.
+   *
+   * An optional link index may be passed.
+   *
+   * @param string|\Drupal\Component\Render\MarkupInterface $label
+   *   Text between the anchor tags.
+   *
+   * @deprecated Scheduled for removal in Drupal 9.0.0.
+   *   Use $this->assertSession()->linkNotExists() instead.
+   */
+  protected function assertNoLink($label) {
+    return $this->assertSession()->linkNotExists($label);
+  }
+
+  /**
+   * Passes if a link containing a given href (part) is found.
+   *
+   * @param string $href
+   *   The full or partial value of the 'href' attribute of the anchor tag.
+   * @param int $index
+   *   Link position counting from zero.
+   *
+   * @deprecated Scheduled for removal in Drupal 9.0.0.
+   *   Use $this->assertSession()->linkByHref() instead.
+   */
+  protected function assertLinkByHref($href, $index = 0) {
+    $this->assertSession()->linkByHrefExists($href, $index);
+  }
+
+  /**
+   * Passes if a link containing a given href (part) is not found.
+   *
+   * @param string $href
+   *   The full or partial value of the 'href' attribute of the anchor tag.
+   * @param int $index
+   *   Link position counting from zero.
+   *
+   * @deprecated Scheduled for removal in Drupal 9.0.0.
+   *   Use $this->assertSession()->linkByHrefNotExists() instead.
+   */
+  protected function assertNoLinkByHref($href, $index = 0) {
+    $this->assertSession()->linkByHrefNotExists($href, $index);
+  }
+
+  /**
+   * Asserts that a field does not exist with the given ID and value.
+   *
+   * @param string $id
+   *   ID of field to assert.
+   * @param string $value
+   *   (optional) Value for the field, to assert that the field's value on the
+   *   page doesn't match it. You may pass in NULL to skip checking the value,
+   *   while still checking that the field doesn't exist. However, the default
+   *   value ('') asserts that the field value is not an empty string.
+   *
+   * @deprecated Scheduled for removal in Drupal 9.0.0.
+   *   Use $this->assertSession()->fieldNotExists() or
+   *   $this->assertSession()->fieldValueNotEquals() instead.
+   */
+  protected function assertNoFieldById($id, $value = '') {
+    if ($this->getSession()->getPage()->findField($id)) {
+      $this->assertSession()->fieldValueNotEquals($id, (string) $value);
+    }
+    else {
+      $this->assertSession()->fieldNotExists($id);
+    }
+  }
+
+  /**
+   * Passes if the internal browser's URL matches the given path.
+   *
+   * @param \Drupal\Core\Url|string $path
+   *   The expected system path or URL.
+   *
+   * @deprecated Scheduled for removal in Drupal 9.0.0.
+   *   Use $this->assertSession()->addressEquals() instead.
+   */
+  protected function assertUrl($path) {
+    $this->assertSession()->addressEquals($path);
+  }
+
+  /**
    * Asserts that a select option in the current page exists.
    *
    * @param string $id
@@ -217,20 +317,22 @@ protected function assertNoOption($id, $option) {
   }
 
   /**
-   * Passes if the internal browser's URL matches the given path.
+   * Passes if the raw text IS found escaped on the loaded page, fail otherwise.
    *
-   * @param string $path
-   *   The expected system path.
+   * Raw text refers to the raw HTML that the page generated.
+   *
+   * @param string $raw
+   *   Raw (HTML) string to look for.
    *
    * @deprecated Scheduled for removal in Drupal 9.0.0.
-   *   Use $this->assertSession()->addressEquals() instead.
+   *   Use $this->assertSession()->assertEscaped() instead.
    */
-  protected function assertUrl($path) {
-    $this->assertSession()->addressEquals($path);
+  protected function assertEscaped($raw) {
+    $this->assertSession()->assertEscaped($raw);
   }
 
   /**
-   * Passes if the raw text IS NOT found escaped on the loaded page.
+   * Passes if the raw text is not found escaped on the loaded page.
    *
    * Raw text refers to the raw HTML that the page generated.
    *
@@ -240,8 +342,19 @@ protected function assertUrl($path) {
    * @deprecated Scheduled for removal in Drupal 9.0.0.
    *   Use $this->assertSession()->assertNoEscaped() instead.
    */
-  public function assertNoEscaped($raw) {
+  protected function assertNoEscaped($raw) {
     $this->assertSession()->assertNoEscaped($raw);
   }
 
+  /**
+   * Returns WebAssert object.
+   *
+   * @param string $name
+   *   (optional) Name of the session. Defaults to the active session.
+   *
+   * @return \Drupal\Tests\WebAssert
+   *   A new web-assert option for asserting the presence of elements with.
+   */
+  abstract public function assertSession($name = NULL);
+
 }
diff --git a/core/tests/Drupal/Tests/BrowserTestBase.php b/core/tests/Drupal/Tests/BrowserTestBase.php
index 07e1fa9..6ac6a2b 100644
--- a/core/tests/Drupal/Tests/BrowserTestBase.php
+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -573,40 +573,60 @@ protected function prepareRequest() {
   }
 
   /**
-   * Retrieves a Drupal path or an absolute path.
+   * Builds an a absolute URL from a system path or a URL object.
    *
    * @param string|\Drupal\Core\Url $path
-   *   Drupal path or URL to load into Mink controlled browser.
+   *   A system path or a URL.
    * @param array $options
-   *   (optional) Options to be forwarded to the url generator.
+   *   Options to be passed to Url::fromUri().
    *
    * @return string
-   *   The retrieved HTML string, also available as $this->getRawContent()
+   *   An absolute URL stsring.
    */
-  protected function drupalGet($path, array $options = array()) {
-    $options['absolute'] = TRUE;
-
+  protected function buildUrl($path, array $options = array()) {
     if ($path instanceof Url) {
       $url_options = $path->getOptions();
       $options = $url_options + $options;
       $path->setOptions($options);
-      $url = $path->setAbsolute()->toString();
+      return $path->setAbsolute()->toString();
     }
     // The URL generator service is not necessarily available yet; e.g., in
     // interactive installer tests.
     elseif ($this->container->has('url_generator')) {
-      if (UrlHelper::isExternal($path)) {
-        $url = Url::fromUri($path, $options)->toString();
+      $force_internal = isset($options['external']) && $options['external'] == FALSE;
+      if (!$force_internal && UrlHelper::isExternal($path)) {
+        return Url::fromUri($path, $options)->toString();
       }
       else {
-        // This is needed for language prefixing.
-        $options['path_processing'] = TRUE;
-        $url = Url::fromUri('base:/' . $path, $options)->toString();
+        $uri = $path === '<front>' ? 'base:/' : 'base:/' . $path;
+        // Path processing is needed for language prefixing.  Skip it when a
+        // path that may look like an external URL is being used as internal.
+        $options['path_processing'] = !$force_internal;
+        return Url::fromUri($uri, $options)
+          ->setAbsolute()
+          ->toString();
       }
     }
     else {
-      $url = $this->getAbsoluteUrl($path);
+      return $this->getAbsoluteUrl($path);
     }
+  }
+
+  /**
+   * Retrieves a Drupal path or an absolute path.
+   *
+   * @param string|\Drupal\Core\Url $path
+   *   Drupal path or URL to load into Mink controlled browser.
+   * @param array $options
+   *   (optional) Options to be forwarded to the url generator.
+   *
+   * @return string
+   *   The retrieved HTML string, also available as $this->getRawContent()
+   */
+  protected function drupalGet($path, array $options = array()) {
+    $options['absolute'] = TRUE;
+    $url = $this->buildUrl($path, $options);
+
     $session = $this->getSession();
 
     $this->prepareRequest();
@@ -899,6 +919,12 @@ protected function submitForm(array $edit, $submit, $form_html_id = NULL) {
 
     // Edit the form values.
     foreach ($edit as $name => $value) {
+      // Provide support for 1, 0 for checkboxes instead of TRUE and FALSE.
+      // @todo Get rid of supporting 1/0.
+      if (strpos($name, 'name[') === 0) {
+        $value = (bool) $value;
+      }
+
       $field = $assert_session->fieldExists($name, $form);
       $field->setValue($value);
     }
@@ -1680,64 +1706,11 @@ protected function getTextContent() {
    *   The list of elements matching the xpath expression.
    */
   protected function xpath($xpath, array $arguments = []) {
-    $xpath = $this->buildXPathQuery($xpath, $arguments);
+    $xpath = $this->assertSession()->buildXPathQuery($xpath, $arguments);
     return $this->getSession()->getPage()->findAll('xpath', $xpath);
   }
 
   /**
-   * Builds an XPath query.
-   *
-   * Builds an XPath query by replacing placeholders in the query by the value
-   * of the arguments.
-   *
-   * XPath 1.0 (the version supported by libxml2, the underlying XML library
-   * used by PHP) doesn't support any form of quotation. This function
-   * simplifies the building of XPath expression.
-   *
-   * @param string $xpath
-   *   An XPath query, possibly with placeholders in the form ':name'.
-   * @param array $args
-   *   An array of arguments with keys in the form ':name' matching the
-   *   placeholders in the query. The values may be either strings or numeric
-   *   values.
-   *
-   * @return string
-   *   An XPath query with arguments replaced.
-   */
-  protected function buildXPathQuery($xpath, array $args = array()) {
-    // Replace placeholders.
-    foreach ($args as $placeholder => $value) {
-      // Cast MarkupInterface objects to string.
-      if (is_object($value)) {
-        $value = (string) $value;
-      }
-      // XPath 1.0 doesn't support a way to escape single or double quotes in a
-      // string literal. We split double quotes out of the string, and encode
-      // them separately.
-      if (is_string($value)) {
-        // Explode the text at the quote characters.
-        $parts = explode('"', $value);
-
-        // Quote the parts.
-        foreach ($parts as &$part) {
-          $part = '"' . $part . '"';
-        }
-
-        // Return the string.
-        $value = count($parts) > 1 ? 'concat(' . implode(', \'"\', ', $parts) . ')' : $parts[0];
-      }
-
-      // Use preg_replace_callback() instead of preg_replace() to prevent the
-      // regular expression engine from trying to substitute backreferences.
-      $replacement = function ($matches) use ($value) {
-        return $value;
-      };
-      $xpath = preg_replace_callback('/' . preg_quote($placeholder) . '\b/', $replacement, $xpath);
-    }
-    return $xpath;
-  }
-
-  /**
    * Configuration accessor for tests. Returns non-overridden configuration.
    *
    * @param string $name
diff --git a/core/tests/Drupal/Tests/WebAssert.php b/core/tests/Drupal/Tests/WebAssert.php
index ec31fdf..972d086 100644
--- a/core/tests/Drupal/Tests/WebAssert.php
+++ b/core/tests/Drupal/Tests/WebAssert.php
@@ -208,10 +208,135 @@ public function linkExists($label, $index = 0, $message = '') {
     $label = (string) $label;
     $message = ($message ? $message : strtr('Link with label %label found.', ['%label' => $label]));
     $links = $this->session->getPage()->findAll('named', ['link', $label]);
-    if (empty($links[$index])) {
-      throw new ExpectationException($message);
+    $this->assert(!empty($links[$index]), $message);
+  }
+
+  /**
+   * Passes if a link with the specified label is not found.
+   *
+   * An optional link index may be passed.
+   *
+   * @param string|\Drupal\Component\Render\MarkupInterface $label
+   *   Text between the anchor tags.
+   * @param string $message
+   *   (optional) A message to display with the assertion. Do not translate
+   *   messages: use strtr() to embed variables in the message text, not
+   *   t(). If left blank, a default message will be displayed.
+   *
+   * @throws \Behat\Mink\Exception\ExpectationException
+   *   Thrown when element doesn't exist, or the link label is a different one.
+   */
+  public function linkNotExists($label, $message = '') {
+    $message = ($message ? $message : strtr('Link with label %label found.', ['%label' => $label]));
+    $links = $this->session->getPage()->findAll('named', ['link', $label]);
+    $this->assert(empty($links), $message);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fieldValueEquals($field, $value, TraversableElement $container = NULL) {
+    parent::fieldValueEquals($field, $value, $container);
+  }
+
+  /**
+   * Passes if a link containing a given href (part) is found.
+   *
+   * @param string $href
+   *   The full or partial value of the 'href' attribute of the anchor tag.
+   * @param int $index
+   *   Link position counting from zero.
+   * @param string $message
+   *   (optional) A message to display with the assertion. Do not translate
+   *   messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed
+   *   variables in the message text, not t(). If left blank, a default message
+   *   will be displayed.
+   *
+   * @throws \Behat\Mink\Exception\ExpectationException
+   *   Thrown when element doesn't exist, or the link label is a different one.
+   */
+  public function linkByHrefExists($href, $index = 0, $message = '') {
+    $xpath = $this->buildXPathQuery('//a[contains(@href, :href)]', [':href' => $href]);
+    $message = ($message ? $message : strtr('Link containing href %href found.', ['%href' => $href]));
+    $links = $this->session->getPage()->findAll('xpath', $xpath);
+    $this->assert(!empty($links[$index]), $message);
+  }
+
+  /**
+   * Passes if a link containing a given href (part) is not found.
+   *
+   * @param string $href
+   *   The full or partial value of the 'href' attribute of the anchor tag.
+   * @param int $index
+   *   Link position counting from zero.
+   * @param string $message
+   *   (optional) A message to display with the assertion. Do not translate
+   *   messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed
+   *   variables in the message text, not t(). If left blank, a default message
+   *   will be displayed.
+   *
+   * @throws \Behat\Mink\Exception\ExpectationException
+   *   Thrown when element doesn't exist, or the link label is a different one.
+   */
+  public function linkByHrefNotExists($href, $index = 0, $message = '') {
+    // Cast MarkupInterface objects to string.
+    $xpath = $this->buildXPathQuery('//a[contains(@href, :href)]', [':href' => $href]);
+    $message = ($message ? $message : strtr('Link containing href %href found.', ['%href' => $href]));
+    $links = $this->session->getPage()->findAll('xpath', $xpath);
+    $this->assert(empty($links[$index]), $message);
+  }
+
+  /**
+   * Builds an XPath query.
+   *
+   * Builds an XPath query by replacing placeholders in the query by the value
+   * of the arguments.
+   *
+   * XPath 1.0 (the version supported by libxml2, the underlying XML library
+   * used by PHP) doesn't support any form of quotation. This function
+   * simplifies the building of XPath expression.
+   *
+   * @param string $xpath
+   *   An XPath query, possibly with placeholders in the form ':name'.
+   * @param array $args
+   *   An array of arguments with keys in the form ':name' matching the
+   *   placeholders in the query. The values may be either strings or numeric
+   *   values.
+   *
+   * @return string
+   *   An XPath query with arguments replaced.
+   */
+  public function buildXPathQuery($xpath, array $args = array()) {
+    // Replace placeholders.
+    foreach ($args as $placeholder => $value) {
+      // Cast MarkupInterface objects to string.
+      if (is_object($value)) {
+        throw new \InvalidArgumentException('Just pass in scalar values.');
+      }
+      // XPath 1.0 doesn't support a way to escape single or double quotes in a
+      // string literal. We split double quotes out of the string, and encode
+      // them separately.
+      if (is_string($value)) {
+        // Explode the text at the quote characters.
+        $parts = explode('"', $value);
+
+        // Quote the parts.
+        foreach ($parts as &$part) {
+          $part = '"' . $part . '"';
+        }
+
+        // Return the string.
+        $value = count($parts) > 1 ? 'concat(' . implode(', \'"\', ', $parts) . ')' : $parts[0];
+      }
+
+      // Use preg_replace_callback() instead of preg_replace() to prevent the
+      // regular expression engine from trying to substitute backreferences.
+      $replacement = function ($matches) use ($value) {
+        return $value;
+      };
+      $xpath = preg_replace_callback('/' . preg_quote($placeholder) . '\b/', $replacement, $xpath);
     }
-    $this->assert($links[$index] !== NULL, $message);
+    return $xpath;
   }
 
   /**
@@ -223,7 +348,19 @@ public function linkExists($label, $index = 0, $message = '') {
    *   Raw (HTML) string to look for.
    */
   public function assertNoEscaped($raw) {
-    $this->pageTextNotContains(Html::escape($raw));
+    $this->responseNotContains(Html::escape($raw));
+  }
+
+  /**
+   * Passes if the raw text IS found escaped on the loaded page.
+   *
+   * Raw text refers to the raw HTML that the page generated.
+   *
+   * @param string $raw
+   *   Raw (HTML) string to look for.
+   */
+  public function assertEscaped($raw) {
+    $this->responseContains(Html::escape($raw));
   }
 
   /**
