diff --git a/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php b/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php
index cc87d283b5..a698399c0e 100644
--- a/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php
+++ b/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php
@@ -96,14 +96,14 @@ public function testBlocks($theme, $block_plugin, $new_page_text, $element_selec
       if ($element = $page->find('css', "#toolbar-administration a.is-active")) {
         // If a tray was open from page load close it.
         $element->click();
-        $this->waitForNoElement("#toolbar-administration a.is-active");
+        $web_assert->assertNoElementAfterWait('css', "#toolbar-administration a.is-active");
       }
       $page->find('css', $toolbar_item)->click();
       $this->assertElementVisibleAfterWait('css', "{$toolbar_item}.is-active");
     }
     $this->enableEditMode();
     if (isset($toolbar_item)) {
-      $this->waitForNoElement("{$toolbar_item}.is-active");
+      $web_assert->assertNoElementAfterWait('css',"{$toolbar_item}.is-active");
     }
     $this->openBlockForm($block_selector);
     switch ($block_plugin) {
@@ -158,7 +158,7 @@ public function testBlocks($theme, $block_plugin, $new_page_text, $element_selec
     $this->waitForOffCanvasToClose();
     $this->getSession()->wait(100);
     $this->assertEditModeDisabled();
-    $web_assert->elementTextContains('css', '#drupal-live-announce', 'Exited edit mode.');
+    $web_assert->waitForElement('css', '#drupal-live-announce:contains(Exited edit mode)');
     $web_assert->elementTextNotContains('css', '.contextual-toolbar-tab button', 'Editing');
     $web_assert->elementAttributeNotContains('css', '.dialog-off-canvas-main-canvas', 'class', 'js-settings-tray-edit-mode');
   }
diff --git a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.es6.js b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.es6.js
new file mode 100644
index 0000000000..a22c818079
--- /dev/null
+++ b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.es6.js
@@ -0,0 +1,30 @@
+/**
+ * @file
+ *  Testing behavior for JSWebAssertTest.
+ */
+
+(($, Drupal) => {
+  /**
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Makes changes in the DOM to be able to test the completion of AJAX in assertWaitOnAjaxRequest.
+   */
+  Drupal.behaviors.js_webassert_test_wait_for_ajax_request = {
+    attach() {
+      $('#edit-test-assert-no-element-after-wait-pass').on('click', (e) => {
+        e.preventDefault();
+        setTimeout(() => {
+          $('#edit-test-assert-no-element-after-wait-pass').remove();
+        }, 500);
+      });
+
+      $('#edit-test-assert-no-element-after-wait-fail').on('click', (e) => {
+        e.preventDefault();
+        setTimeout(() => {
+          $('#edit-test-assert-no-element-after-wait-fail').remove();
+        }, 2000);
+      });
+    },
+  };
+})(jQuery, Drupal);
diff --git a/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.js b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.js
new file mode 100644
index 0000000000..c529bb3e12
--- /dev/null
+++ b/core/modules/system/tests/modules/js_webassert_test/js/js_webassert_test.no_element_after_wait.js
@@ -0,0 +1,26 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+
+(function ($, Drupal) {
+  Drupal.behaviors.js_webassert_test_wait_for_ajax_request = {
+    attach: function attach() {
+      $('#edit-test-assert-no-element-after-wait-pass').on('click', function (e) {
+        e.preventDefault();
+        setTimeout(function () {
+          $('#edit-test-assert-no-element-after-wait-pass').remove();
+        }, 500);
+      });
+
+      $('#edit-test-assert-no-element-after-wait-fail').on('click', function (e) {
+        e.preventDefault();
+        setTimeout(function () {
+          $('#edit-test-assert-no-element-after-wait-fail').remove();
+        }, 2000);
+      });
+    }
+  };
+})(jQuery, Drupal);
\ No newline at end of file
diff --git a/core/modules/system/tests/modules/js_webassert_test/js_webassert_test.libraries.yml b/core/modules/system/tests/modules/js_webassert_test/js_webassert_test.libraries.yml
index 3a17b1dcf4..f14c27679a 100644
--- a/core/modules/system/tests/modules/js_webassert_test/js_webassert_test.libraries.yml
+++ b/core/modules/system/tests/modules/js_webassert_test/js_webassert_test.libraries.yml
@@ -12,3 +12,11 @@ wait_for_element:
   dependencies:
     - core/jquery
     - core/drupal
+
+no_element_after_wait:
+  version: VERSION
+  js:
+    js/js_webassert_test.no_element_after_wait.js: {}
+  dependencies:
+    - core/jquery
+    - core/drupal
\ No newline at end of file
diff --git a/core/modules/system/tests/modules/js_webassert_test/src/Form/JsWebAssertTestForm.php b/core/modules/system/tests/modules/js_webassert_test/src/Form/JsWebAssertTestForm.php
index d46db774d6..b4db62fbc3 100644
--- a/core/modules/system/tests/modules/js_webassert_test/src/Form/JsWebAssertTestForm.php
+++ b/core/modules/system/tests/modules/js_webassert_test/src/Form/JsWebAssertTestForm.php
@@ -113,6 +113,22 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         'wrapper' => 'js_webassert_test_form_wrapper',
       ],
     ];
+
+    // Button to test the assertNoElementAfterWait() assertion, will pass.
+    $form['test_assert_no_element_after_wait_pass'] = [
+      '#type' => 'submit',
+      '#value' => $this->t('Test assertNoElementAfterWait: pass'),
+      '#button_type' => 'primary',
+      '#attached' => ['library' => 'js_webassert_test/no_element_after_wait'],
+    ];
+
+    // Button to test the assertNoElementAfterWait() assertion, will fail.
+    $form['test_assert_no_element_after_wait_fail'] = [
+      '#type' => 'submit',
+      '#value' => $this->t('Test assertNoElementAfterWait: fail'),
+      '#button_type' => 'primary',
+    ];
+
     return $form;
   }
 
diff --git a/core/modules/system/tests/src/FunctionalJavascript/OffCanvasTestBase.php b/core/modules/system/tests/src/FunctionalJavascript/OffCanvasTestBase.php
index d3f446cf6a..a64ff9838b 100644
--- a/core/modules/system/tests/src/FunctionalJavascript/OffCanvasTestBase.php
+++ b/core/modules/system/tests/src/FunctionalJavascript/OffCanvasTestBase.php
@@ -41,7 +41,7 @@ protected function assertPageLoadComplete() {
    * @todo Move this function to https://www.drupal.org/node/2821724.
    */
   protected function assertAllContextualLinksLoaded() {
-    $this->waitForNoElement('[data-contextual-id]:empty');
+    $this->assertSession()->assertNoElementAfterWait('css', '[data-contextual-id]:empty');
   }
 
   /**
@@ -74,7 +74,7 @@ protected function waitForOffCanvasToOpen() {
    * Waits for off-canvas dialog to close.
    */
   protected function waitForOffCanvasToClose() {
-    $this->waitForNoElement('#drupal-off-canvas');
+    $this->assertSession()->assertNoElementAfterWait('css','#drupal-off-canvas');
   }
 
   /**
@@ -88,21 +88,6 @@ protected function getOffCanvasDialog() {
     return $off_canvas_dialog;
   }
 
-  /**
-   * Waits for an element to be removed from the page.
-   *
-   * @param string $selector
-   *   CSS selector.
-   * @param int $timeout
-   *   (optional) Timeout in milliseconds, defaults to 10000.
-   *
-   * @todo Remove in https://www.drupal.org/node/2892440.
-   */
-  protected function waitForNoElement($selector, $timeout = 10000) {
-    $condition = "(typeof jQuery !== 'undefined' && jQuery('$selector').length === 0)";
-    $this->assertJsCondition($condition, $timeout);
-  }
-
   /**
    * Get themes to test.
    *
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php b/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php
index 281cb78348..f716d72ac5 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php
@@ -366,4 +366,35 @@ function t(r, lx, ly) {
     return $this->session->evaluateScript($full_javascript_visibility_test);
   }
 
+  /**
+   * Asserts that no matching element existss on the page after a wait.
+   *
+   * @param string $selector_type
+   *   The element selector type (CSS, XPath).
+   * @param string|array $selector
+   *   The element selector.
+   * @param int $timeout
+   *   (optional) Timeout in milliseconds, defaults to 10000.
+   */
+  public function assertNoElementAfterWait($selector_type, $selector, $timeout = 10000, $message = 'Element exists on the page.') {
+
+    $start = microtime(TRUE);
+    $end = $start + ($timeout / 1000);
+    $page = $this->session->getPage();
+
+    do {
+      $node = $page->find($selector_type, $selector);
+
+      if (empty($node)) {
+        return;
+      }
+      usleep(100000);
+    } while (microtime(TRUE) < $end);
+
+    if ($node) {
+      throw new ElementHtmlException($message, $this->session->getDriver(), $node);
+    }
+  }
+
+
 }
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Tests/JSWebAssertTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Tests/JSWebAssertTest.php
index 36f6340f72..abeb99d8dd 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/Tests/JSWebAssertTest.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/Tests/JSWebAssertTest.php
@@ -29,6 +29,17 @@ public function testJsWebAssert() {
     $assert_session = $this->assertSession();
     $page = $session->getPage();
 
+    $assert_session->elementExists('css', '[data-drupal-selector="edit-test-assert-no-element-after-wait-pass"]');
+    $page->findButton('Test assertNoElementAfterWait: pass')->press();
+    $assert_session->assertNoElementAfterWait('css', '[data-drupal-selector="edit-test-assert-no-element-after-wait-pass"]',1000);
+
+    $assert_session->elementExists('css', '[data-drupal-selector="edit-test-assert-no-element-after-wait-fail"]');
+    $page->findButton('Test assertNoElementAfterWait: fail')->press();
+    $this->setExpectedException('\Behat\Mink\Exception\ElementHtmlException', 'Element exists on page after too short wait.');
+    $assert_session->assertNoElementAfterWait('css', '[data-drupal-selector="edit-test-assert-no-element-after-wait-fail"]', 500, 'Element exists on page after too short wait.');
+
+    $assert_session->assertNoElementAfterWait('css', '[data-drupal-selector="edit-test-assert-no-element-after-wait-fail"]', 2500, 'Element remove after another wait.ss');
+
     $test_button = $page->findButton('Add button');
     $test_link = $page->findButton('Add link');
     $test_field = $page->findButton('Add field');
