diff --git a/tests/src/FunctionalJavascript/CheckoutTest.php b/tests/src/FunctionalJavascript/CheckoutTest.php
index 3cec3ef..abaccce 100644
--- a/tests/src/FunctionalJavascript/CheckoutTest.php
+++ b/tests/src/FunctionalJavascript/CheckoutTest.php
@@ -210,17 +210,7 @@ class CheckoutTest extends CommerceWebDriverTestBase {
     $this->assertWaitForText('Visa ending in 3155');
     $this->assertWaitForText('Expires 3/2022');
     $this->getSession()->getPage()->pressButton('Pay and complete purchase');
-
-    $this->assertWaitForFrame('__privateStripeFrame4');
-    $this->getSession()->switchToIFrame('__privateStripeFrame4');
-    $this->assertWaitForFrame('challengeFrame');
-    $this->getSession()->switchToIFrame('challengeFrame');
-    // Asset wait for text does not work in the iframe for some reason.
-    sleep(1);
-    $this->assertWaitForText('This is a test payment of $9.99 using 3D Secure.');
-    $button = $pass ? 'Complete authentication' : 'Fail authentication';
-    $this->getSession()->getPage()->pressButton($button);
-    $this->getSession()->switchToIFrame();
+    $this->complete3ds($pass);
 
     if ($pass) {
       $this->assertWaitForText('Your order number is 1. You can view your order on your account page when logged in.');
@@ -275,16 +265,8 @@ class CheckoutTest extends CommerceWebDriverTestBase {
     $this->assertWaitForText('Expires 3/2022');
     $this->getSession()->getPage()->pressButton('Pay and complete purchase');
 
-    $this->assertWaitForFrame('__privateStripeFrame4');
-    $this->getSession()->switchToIFrame('__privateStripeFrame4');
-    $this->assertWaitForFrame('challengeFrame');
-    $this->getSession()->switchToIFrame('challengeFrame');
-    // Asset wait for text does not work in the iframe for some reason.
-    sleep(1);
-    $this->assertWaitForText('This is a test payment of $9.99 using 3D Secure.');
-    $button = $pass ? 'Complete authentication' : 'Fail authentication';
-    $this->getSession()->getPage()->pressButton($button);
-    $this->getSession()->switchToIFrame();
+    $this->complete3ds($pass);
+
     if ($pass) {
       $this->assertWaitForText('Your order number is 1. You can view your order on your account page when logged in.');
     }
@@ -320,15 +302,7 @@ class CheckoutTest extends CommerceWebDriverTestBase {
       'payment_method[billing_information][address][0][address][postal_code]' => '10001',
     ], 'Save');
 
-    $this->assertWaitForFrame('__privateStripeFrame9');
-    $this->getSession()->switchToIFrame('__privateStripeFrame9');
-    $this->assertWaitForFrame('challengeFrame');
-    $this->getSession()->switchToIFrame('challengeFrame');
-    // Asset wait for text does not work in the iframe for some reason.
-    sleep(1);
-    $this->assertWaitForText('This is a 3D Secure non-payment authentication test page.');
-    $this->getSession()->getPage()->pressButton('Complete authentication');
-    $this->getSession()->switchToIFrame();
+    $this->complete3ds(TRUE, FALSE);
 
     $this->assertWaitForText('Visa ending in ' . substr($card_number, -4) . ' saved to your payment methods.');
     $this->drupalGet(Url::fromRoute('entity.commerce_payment_method.collection', [
@@ -349,16 +323,7 @@ class CheckoutTest extends CommerceWebDriverTestBase {
     $this->assertSession()->pageTextContains('Order Summary');
     $this->getSession()->getPage()->pressButton('Pay and complete purchase');
 
-
-    $this->assertWaitForFrame('__privateStripeFrame4');
-    $this->getSession()->switchToIFrame('__privateStripeFrame4');
-    $this->assertWaitForFrame('challengeFrame');
-    $this->getSession()->switchToIFrame('challengeFrame');
-    // Asset wait for text does not work in the iframe for some reason.
-    sleep(1);
-    $this->assertWaitForText('This is a test payment of $9.99 using 3D Secure.');
-    $this->getSession()->getPage()->pressButton('Complete authentication');
-    $this->getSession()->switchToIFrame();
+    $this->complete3ds(TRUE);
 
     $this->assertWaitForText('Your order number is 1. You can view your order on your account page when logged in.');
   }
@@ -390,15 +355,7 @@ class CheckoutTest extends CommerceWebDriverTestBase {
       'payment_method[billing_information][address][0][address][postal_code]' => '10001',
     ], 'Save');
 
-    $this->assertWaitForFrame('__privateStripeFrame9');
-    $this->getSession()->switchToIFrame('__privateStripeFrame9');
-    $this->assertWaitForFrame('challengeFrame');
-    $this->getSession()->switchToIFrame('challengeFrame');
-    // Asset wait for text does not work in the iframe for some reason.
-    sleep(1);
-    $this->assertWaitForText('This is a 3D Secure non-payment authentication test page.');
-    $this->getSession()->getPage()->pressButton('Complete authentication');
-    $this->getSession()->switchToIFrame();
+    $this->complete3ds(TRUE, FALSE);
 
     $this->assertWaitForText('Visa ending in ' . substr($card_number, -4) . ' saved to your payment methods.');
     $this->drupalGet(Url::fromRoute('entity.commerce_payment_method.collection', [
@@ -596,13 +553,15 @@ class CheckoutTest extends CommerceWebDriverTestBase {
    *
    * @throws \Exception
    */
-  public function assertWaitForFrame($name, $wait = 20) {
+  public function switchToFrame($name, $wait = 20) {
     $last_exception = NULL;
     $stopTime = time() + $wait;
     while (time() < $stopTime) {
       try {
         $this->assertSession()->elementExists('xpath', "//iframe[@id='$name' or @name='$name']");
-        return TRUE;
+        $this->getSession()->switchToIFrame($name);
+        sleep(1);
+        return;
       }
       catch (\Exception $e) {
         // If the frame has not been found, keep waiting.
@@ -613,4 +572,30 @@ class CheckoutTest extends CommerceWebDriverTestBase {
     throw $last_exception;
   }
 
+  /**
+   * Completes 3DS authentication using Stripe's modal.
+   *
+   * @param $pass
+   *   Whether to pass or fail the 3DS authentication.
+   * @param $payment
+   *   Whether this is a payment or non-payment 3DS.
+   *
+   * @throws \Behat\Mink\Exception\ElementNotFoundException
+   */
+  protected function complete3ds($pass, $payment = TRUE) {
+    $stripeFrame = '__privateStripeFrame9';
+    $text = 'This is a 3D Secure non-payment authentication test page.';
+    if ($payment) {
+      $stripeFrame = '__privateStripeFrame4';
+      $text = '3D Secure Test Payment Page';
+    }
+    $this->switchToFrame($stripeFrame);
+    $this->switchToFrame('challengeFrame');
+    $this->switchToFrame('acsFrame');
+    $this->assertWaitForText($text);
+    $button = $pass ? 'Complete authentication' : 'Fail authentication';
+    $this->getSession()->getPage()->pressButton($button);
+    $this->getSession()->switchToIFrame();
+  }
+
 }
