diff --git a/core/tests/Drupal/FunctionalTests/Entity/RevisionVersionHistoryTranslatableTest.php b/core/tests/Drupal/FunctionalTests/Entity/RevisionVersionHistoryTranslatableTest.php
index cea79f4b55bfea851bc8d03b90135b0d629f216a..4550597e6f6d24379f7d92e163981128a9806880 100644
--- a/core/tests/Drupal/FunctionalTests/Entity/RevisionVersionHistoryTranslatableTest.php
+++ b/core/tests/Drupal/FunctionalTests/Entity/RevisionVersionHistoryTranslatableTest.php
@@ -75,14 +75,8 @@ public function testVersionHistoryTranslations(): void {
     $this->assertSession()->linkByHrefNotExists($firstRevision->getTranslation('es')->toUrl('revision-delete-form')->toString());
 
     $this->drupalGet($entity->getTranslation('es')->toUrl('version-history'));
-    // We can't use linkByHrefNotExists here because it does a "contains" match
-    // and the translated URLs contain the non translated ones.
-    // i.e /es/entity_test_mul_revlog/1/revision/1/revert contains
-    // /entity_test_mul_revlog/1/revision/1/revert.
-    $xpath = $this->assertSession()->buildXPathQuery('//a[@href=:href]', [':href' => $firstRevision->toUrl('revision-revert-form')->toString()]);
-    $this->assertEmpty($this->getSession()->getPage()->findAll('xpath', $xpath));
-    $xpath = $this->assertSession()->buildXPathQuery('//a[@href=:href]', [':href' => $firstRevision->toUrl('revision-delete-form')->toString()]);
-    $this->assertEmpty($this->getSession()->getPage()->findAll('xpath', $xpath));
+    $this->assertSession()->linkByHrefNotExistsExact($firstRevision->toUrl('revision-revert-form')->toString());
+    $this->assertSession()->linkByHrefNotExistsExact($firstRevision->toUrl('revision-delete-form')->toString());
     $this->assertSession()->linkByHrefExists($firstRevision->getTranslation('es')->toUrl('revision-revert-form')->toString());
     $this->assertSession()->linkByHrefExists($firstRevision->getTranslation('es')->toUrl('revision-delete-form')->toString());
   }
diff --git a/core/tests/Drupal/FunctionalTests/WebAssertTest.php b/core/tests/Drupal/FunctionalTests/WebAssertTest.php
index 81d5c7402019c84a6b7d013669aaa83fb32a1810..9739038473c5ae8a18188f5560adcd9984506686 100644
--- a/core/tests/Drupal/FunctionalTests/WebAssertTest.php
+++ b/core/tests/Drupal/FunctionalTests/WebAssertTest.php
@@ -189,6 +189,104 @@ public function testInvalidLinkNotExistsExact() {
     $this->assertSession()->linkNotExistsExact('foo|bar|baz');
   }
 
+  /**
+   * Tests linkExistsByHref() functionality.
+   *
+   * @covers ::linkByHrefExists
+   */
+  public function testLinkByHrefExists(): void {
+    $this->drupalGet('test-page');
+    // Partial matching.
+    $this->assertSession()->linkByHrefExists('/user');
+    // Full matching.
+    $this->assertSession()->linkByHrefExists('/user/login');
+  }
+
+  /**
+   * Tests linkExistsByHref() functionality fail.
+   *
+   * @covers ::linkByHrefExists
+   */
+  public function testInvalidLinkByHrefExists(): void {
+    $this->drupalGet('test-page');
+    $this->expectException(ExpectationException::class);
+    $this->assertSession()->linkByHrefExists('/foo');
+  }
+
+  /**
+   * Tests linkByHrefNotExists() functionality.
+   *
+   * @covers ::linkByHrefNotExists
+   */
+  public function testLinkByHrefNotExists(): void {
+    $this->drupalGet('test-page');
+    $this->assertSession()->linkByHrefNotExists('/foo');
+  }
+
+  /**
+   * Tests LinkByHrefNotExists() functionality fail partial match.
+   *
+   * @covers ::linkByHrefNotExists
+   */
+  public function testInvalidLinkByHrefNotExistsPartial(): void {
+    $this->drupalGet('test-page');
+    $this->expectException(ExpectationException::class);
+    $this->assertSession()->linkByHrefNotExists('/user');
+  }
+
+  /**
+   * Tests LinkByHrefNotExists() functionality fail full match.
+   *
+   * @covers ::linkByHrefNotExists
+   */
+  public function testInvalidLinkByHrefNotExistsFull(): void {
+    $this->drupalGet('test-page');
+    $this->expectException(ExpectationException::class);
+    $this->assertSession()->linkByHrefNotExists('/user/login');
+  }
+
+  /**
+   * Tests linkExistsByHref() functionality.
+   *
+   * @covers ::linkByHrefExistsExact
+   */
+  public function testLinkByHrefExistsExact(): void {
+    $this->drupalGet('test-page');
+    $this->assertSession()->linkByHrefExistsExact('/user/login');
+  }
+
+  /**
+   * Tests linkByHrefExistsExact() functionality fail.
+   *
+   * @covers ::linkByHrefExistsExact
+   */
+  public function testInvalidLinkByHrefExistsExact(): void {
+    $this->drupalGet('test-page');
+    $this->expectException(ExpectationException::class);
+    $this->assertSession()->linkByHrefExistsExact('/foo');
+  }
+
+  /**
+   * Tests linkByHrefNotExistsExact() functionality.
+   *
+   * @covers ::linkByHrefNotExistsExact
+   */
+  public function testLinkByHrefNotExistsExact(): void {
+    $this->drupalGet('test-page');
+    $this->assertSession()->linkByHrefNotExistsExact('/foo');
+  }
+
+  /**
+   * Tests linkByHrefNotExistsExact() functionality fail.
+   *
+   * @covers ::linkByHrefNotExistsExact
+   */
+  public function testInvalidLinkByHrefNotExistsExact(): void {
+    $this->drupalGet('test-page');
+    $this->expectException(ExpectationException::class);
+    $this->assertSession()->linkByHrefNotExistsExact('/user/login');
+  }
+
   /**
    * Tests legacy text asserts.
    *
diff --git a/core/tests/Drupal/Tests/WebAssert.php b/core/tests/Drupal/Tests/WebAssert.php
index bb6f2bea2e3ae0ccdb006bfd46872cb207c3930d..d8f9006e3fd5c5ecfb3d89c3bac1405eb934327c 100644
--- a/core/tests/Drupal/Tests/WebAssert.php
+++ b/core/tests/Drupal/Tests/WebAssert.php
@@ -387,6 +387,29 @@ public function linkByHrefExists($href, $index = 0, $message = '') {
     $this->assert(!empty($links[$index]), $message);
   }
 
+  /**
+   * Passes if a link with a given href is found.
+   *
+   * @param string $href
+   *   The full 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\Render\FormattableMarkup 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 linkByHrefExistsExact(string $href, int $index = 0, string $message = ''): void {
+    $xpath = $this->buildXPathQuery('//a[@href=:href]', [':href' => $href]);
+    $message = ($message ?: strtr('No link with 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.
    *
@@ -408,6 +431,27 @@ public function linkByHrefNotExists($href, $message = '') {
     $this->assert(empty($links), $message);
   }
 
+  /**
+   * Passes if a link with a given href is not found.
+   *
+   * @param string $href
+   *   The full value of the 'href' attribute of the anchor tag.
+   * @param string $message
+   *   (optional) A message to display with the assertion. Do not translate
+   *   messages: use \Drupal\Component\Render\FormattableMarkup 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 linkByHrefNotExistsExact(string $href, string $message = ''): void {
+    $xpath = $this->buildXPathQuery('//a[@href=:href]', [':href' => $href]);
+    $message = ($message ?: strtr('Link with href %href found.', ['%href' => $href]));
+    $links = $this->session->getPage()->findAll('xpath', $xpath);
+    $this->assert(empty($links), $message);
+  }
+
   /**
    * Builds an XPath query.
    *