diff --git a/commerce_checkout_login.info b/commerce_checkout_login.info
index 0dbbab7..4e0611e 100644
--- a/commerce_checkout_login.info
+++ b/commerce_checkout_login.info
@@ -1,10 +1,13 @@
 name = Checkout Login
 description = Adds an inline login form to the Account Information checkout pane.
 package = Commerce (contrib)
+dependencies[] = commerce
 dependencies[] = commerce_checkout
 dependencies[] = commerce_order
 dependencies[] = commerce_product_reference
 core = 7.x
 
-; Simpletests
-files[] = tests/commerce_checkout_login.test
+files[] = tests/CommerceCheckoutLoginTestBase.php
+files[] = tests/CommerceCheckoutLoginGuestCheckoutTest.test
+files[] = tests/CommerceCheckoutLoginUserLoginTest.test
+files[] = tests/CommerceCheckoutLoginUserRegisterTest.test
diff --git a/commerce_checkout_login.module b/commerce_checkout_login.module
index 63754d7..4696633 100644
--- a/commerce_checkout_login.module
+++ b/commerce_checkout_login.module
@@ -2,193 +2,102 @@
 
 /**
  * @file
- * Adds an inline login form to the Account Information checkout pane.
+ * Adds a new checkout pane to allow users to login, create an account or
+ * checkout anonymously depending on site configuration.
  */
 
-
 /**
  * Implements hook_form_FORM_ID_alter().
- *
- * This module works by altering the checkout form to add an additional bit of
- * AJAX to the Account Information checkout pane via this hook.
  */
-function commerce_checkout_login_form_commerce_checkout_form_alter(&$form, &$form_state) {
-  global $user;
-
-  // If the Account Information pane is on the current checkout page and the
-  // user is not logged in...
-  if (!$user->uid && !empty($form['account'])) {
-    $form['account']['login']['mail'] += array(
-      '#ajax' => array(
-        'callback' => 'commerce_checkout_login_checkout_form_refresh',
-        'wrapper' => 'account-login-container',
-      ),
-    );
-
-    // Immediately validate e-mail addresses if mail confirmation is enabled.
-    if (isset($form['account']['login']['mail_confirm'])) {
-      $form['account']['login']['mail_confirm']['#ajax'] = array(
-        'callback' => 'commerce_checkout_login_checkout_form_refresh',
-        'wrapper' => 'account-login-container',
-      );
-    }
-
-    // Check the form state to see if an e-mail address has been specified.
-    if (!empty($form_state['values']['account']['login'])) {
-      $mail = trim($form_state['values']['account']['login']['mail']);
-
-      // Don't attempt to load the user for an invalid e-mail address.
-      if (_validate_email($mail) && user_load_by_mail($mail)) {
-        // An existing e-mail address has been entered. Add a password field to
-        // allow the customer to login.
-        // @todo: autosubmit by ajax, but only if password was changed to
-        // prevent infinite loops caused by automatically filled forms.
-        $form['account']['login']['password'] = array(
-          '#type' => 'password',
-          '#title' => t('Password'),
-          '#required' => TRUE,
-          '#description' => t('Please enter the password for your account. !forgot', array('!forgot' => l(t('Did you forget your password?'), 'user/password')))
-        );
-
-        // No e-mail confirmation is required to login. So we hide the e-mail
-        // confirmation field if it is set.
-        if (isset($form['account']['login']['mail_confirm'])) {
-          $form['account']['login']['mail_confirm']['#value'] = $mail;
-          $form['account']['login']['mail_confirm']['#access'] = FALSE;
-        }
-      }
+function commerce_checkout_login_form_commerce_checkout_form_account_alter(&$form, &$form_state, $form_id) {
+  if (variable_get('commerce_checkout_login_allow_anonymous_checkout', TRUE)) {
+    // Set the name to guest to differentiate during validation.
+    $form['buttons']['continue']['#name'] = 'guest';
+    // Guest checkout does not need any validation.
+    $form['buttons']['continue']['#limit_validation_errors'] = array();
+    // Change the button label if the register/login form is shown.
+    if ($form_state['account']->uid === 0) {
+      $form['buttons']['continue']['#value'] = t('Checkout as guest');
     }
   }
-}
-
-/**
- * Ajax callback: returns the account information pane to an AJAX request.
- */
-function commerce_checkout_login_checkout_form_refresh($form, $form_state) {
-  $show_conf_mail = variable_get('commerce_order_account_pane_mail_double_entry', FALSE);
-
-  $mail = !empty($form_state['values']['account']['login']['mail']) ? trim($form_state['values']['account']['login']['mail']) : '';
-  _validate_email($mail);
-
-  // Just return the new login form if e-mail confirmation is not required.
-  if (!$show_conf_mail) {
-    return $form['account']['login'];
+  else {
+    $form['buttons']['continue']['#access'] = FALSE;
+    unset($form['buttons']['cancel']['#prefix']);
   }
-
-  // Return AJAX commands to set focus to the mail confirmation field for
-  // improved user experience.
-  $commands = array();
-  $commands[] = ajax_command_replace('#' . $form['account']['login']['mail']['#ajax']['wrapper'], drupal_render($form['account']['login']));
-  $commands[] = ajax_command_invoke('[name="account[login][mail_confirm]"]', 'focus');
-  print ajax_render($commands);
-  exit;
 }
 
 /**
- * Implements hook_commerce_checkout_pane_info_alter().
+ * Implements hook_form_alter().
  */
-function commerce_checkout_login_commerce_checkout_pane_info_alter(&$checkout_panes) {
-  if (isset($checkout_panes['account'])) {
-    $checkout_panes['account']['callbacks']['checkout_form_validate'] = 'commerce_checkout_login_commerce_checkout_pane_validate';
-    $checkout_panes['account']['callbacks']['checkout_form_submit'] = 'commerce_checkout_login_commerce_checkout_pane_submit';
+function commerce_checkout_login_form_commerce_checkout_form_checkout_alter(&$form, &$form_state, $form_id) {
+  // If user registration information has been submitted...
+  if (isset($form_state['order']->data['commerce_checkout_login_register'])) {
+    // And the pane has been configured to display account information...
+    if (variable_get('commerce_order_account_pane_auth_display', FALSE)) {
+      // Remove the 'login' form.
+      unset($form['account']['login']);
+      // Display account information.
+      $form['account'][] = ccl_account_information($form_state['order']);
+    }
+    else {
+      // Remove the account pane, because we already have the information.
+      unset($form['account']);
+    }
   }
 }
 
-
 /**
- * Account checkout pane validation.
+ * Implements hook_form_alter().
  */
-function commerce_checkout_login_commerce_checkout_pane_validate(&$form, &$form_state, $checkout_pane, $order) {
-  $mail = !empty($form_state['values']['account']['login']['mail']) ? trim($form_state['values']['account']['login']['mail']) : $form_state['order']->mail;
-
-  // Bail if the e-mail address is invalid.
-  if (!_validate_email($mail)) {
-    return FALSE;
-  }
-
-  if ($account = user_load_by_mail($mail)) {
-    $validated = _validate_existing_account($form, $form_state, $account);
-  }
-  // A non-existing e-mail address has been entered.
-  else {
-    $validated = TRUE;
-    // Validate e-mail confirmation field if set.
-    if (isset($form['account']['login']['mail_confirm'])) {
-      $mail_confirm = !empty($form_state['values']['account']['login']['mail_confirm']) ? trim($form_state['values']['account']['login']['mail_confirm']) : '';
-      if (empty($mail_confirm) || $mail != $mail_confirm) {
-        form_set_error('account][login][mail_confirm', t('The specified e-mail addresses do not match.'));
-        $validated = FALSE;
-      }
-    }
-
-    if (isset($form['account']['login']['password'])) {
-      // A password field is present. During rebuild of the form, this password
-      // field will be removed because a non-existing email address was entered.
-      // Previous form validation might already have set a password required
-      // message. We need to remove said message.
-      $messages = drupal_get_messages('error');
-      $password_title = $form['account']['login']['password']['#title'];
-      foreach ($messages['error'] as $message) {
-        if ($message != strip_tags(t('The field %field is required.', array('%field' => $password_title)))) {
-          // This message is not the password required message, re-set it.
-          drupal_set_message($message, 'error');
-        }
-      }
+function commerce_checkout_login_form_commerce_checkout_form_review_alter(&$form, &$form_state, $form_id) {
+  // If user registration information has been submitted...
+  if (isset($form_state['order']->data['commerce_checkout_login_register'])) {
+    // If the account review pane is shown.
+    if (isset($form['checkout_review']['review']['#data']['account'])) {
+      $content = ccl_account_information($form_state['order']);
+      $form['checkout_review']['review']['#data']['account']['data'] = render($content);
     }
   }
-
-  return $validated;
 }
 
 /**
- * Account checkout pane submit handler.
+ * Implements hook_commerce_checkout_pane_info().
  */
-function commerce_checkout_login_commerce_checkout_pane_submit(&$form, &$form_state, $checkout_pane, $order) {
+function commerce_checkout_login_commerce_checkout_pane_info() {
   global $user;
 
-  // commerce_checkout_login_uid gets set during _validate_existing_account() if
-  // the account was validated successfully.
-  if (!empty($form_state['commerce_checkout_login_uid'])) {
-    // If the user was logged in during this request, make sure we are using the
-    // full user object.
-    if (!empty($user->uid)) {
-      $user = user_load($user->uid);
-    }
-    else {
-      // Load the validated user into the global $user variable.
-      $user = user_load($form_state['commerce_checkout_login_uid']);
-
-      // "Finalize" the login by triggering the appropriate system messages, IP
-      // address and login timestamp logging, and user login hook.
-      user_login_finalize();
-    }
-
-    // Convert the current order from anonymous to authenticated and clear out
-    // our variable from the form state.
-    $oid = is_object($form_state['order']) ? $form_state['order']->order_id : $form_state['order'];
-    $order = commerce_order_load($oid);
-    if (empty($order->uid)) {
-      commerce_checkout_login_order_convert($order, $user);
-    }
-    unset($form_state['commerce_checkout_login_uid']);
-  }
+  $panes['account_form'] = array(
+    'title' => $user->uid > 0 ? t('Account information') : t('Checkout method'),
+    'name' => t('Account'),
+    'page' => 'account',
+    'file' => 'commerce_checkout_login.panes.inc',
+    'callbacks' => array(
+      'settings_form' => 'commerce_checkout_login_account_settings_form',
+      'checkout_form' => 'commerce_checkout_login_account_form',
+      'checkout_form_validate' => 'commerce_checkout_login_account_form_validate',
+      'checkout_form_submit' => 'commerce_checkout_login_account_form_submit',
+    ),
+  );
+
+  return $panes;
 }
 
 /**
- * Email validation helper
+ * Implements hook_commerce_checkout_page_info().
  */
-function _validate_email($mail) {
-  if ($error = user_validate_mail($mail)) {
-    form_set_error('account][login][mail', $error);
-    return FALSE;
-  }
-  return TRUE;
+function commerce_checkout_login_commerce_checkout_page_info() {
+  $pages['account'] = array(
+    'title' => t('Account'),
+    'weight' => -1,
+  );
+
+  return $pages;
 }
 
 /**
  * Known user validation helper.
  */
-function _validate_existing_account(&$form, &$form_state, &$account) {
+function ccl_validate_existing_account(&$form, &$form_state, &$account) {
   if ($user = user_uid_optional_load()) {
     if ($user->uid === $account->uid) {
       // Nothing to validate, the user is already logged in.
@@ -196,67 +105,81 @@ function _validate_existing_account(&$form, &$form_state, &$account) {
     }
   }
 
-  // If there is no password field present, the customer has not yet been
-  // informed about the the pre-existing account. We therefore have to inform
-  // the customer about this.
-  if (!isset($form['account']['login']['password'])) {
-    $message = t('There is already an account registered to %mail. Please enter your password to continue checkout.', array('%mail' => $account->mail));
-    drupal_set_message($message, 'warning');
-    // By invalidating the form submission we trigger a rebuild which will cause
-    // the password field to be rendered.
-    return FALSE;
+  // user_login_authenticate_validate() does a flood controlled authentication
+  // of the credentials based on a form submission. We therefor simulate a form
+  // submission to make use of existing code.
+  $credentials['values'] = array(
+    'pass' => $form_state['values']['account_form']['select']['login']['password'],
+    'name' => $account->name,
+    'mail' => $account->mail,
+  );
+  user_login_authenticate_validate(array(), $credentials);
+  // The uid is added to the credentials when validation is successful.
+  if (isset($credentials['uid']) && $credentials['uid']) {
+    // Clear past failures for this user so as not to block a user who might
+    // log in and out more than once in an hour.
+    if (isset($credentials['flood_control_user_identifier'])) {
+      flood_clear_event('failed_login_attempt_user', $credentials['flood_control_user_identifier']);
+    }
+    $form_state['commerce_checkout_login_uid'] = $credentials['uid'];
+    return TRUE;
   }
   else {
-    // Display an appropriate error message if the user account is blocked.
-    if (user_is_blocked($account->name)) {
-      form_set_error('account][login][email', t('The username %name has not been activated or is blocked.', array('%name' => $account->name)));
-      return FALSE;
+    // Register events for flood control.
+    // Copied/adjusted from user_login_final_validate().
+
+    // Always register an IP-based failed login event.
+    flood_register_event('failed_login_attempt_ip', variable_get('user_failed_login_ip_window', 3600));
+    // Register a per-user failed login event.
+    if (isset($credentials['flood_control_user_identifier'])) {
+      flood_register_event('failed_login_attempt_user', variable_get('user_failed_login_user_window', 21600), $credentials['flood_control_user_identifier']);
     }
 
-    // user_login_authenticate_validate() does a flood controlled authentication
-    // of the credentials based on a form submission. We therefor simulate a
-    // form submission to make use of existing code.
-    $credentials['values'] = array(
-      'pass' => $form_state['values']['account']['login']['password'],
-      'name' => $account->name,
-    );
-    user_login_authenticate_validate(array(), $credentials);
-    // The uid is added to the credentials when validation is successful.
-    if (isset($credentials['uid']) && $credentials['uid']) {
-      // Clear past failures for this user so as not to block a user who might
-      // log in and out more than once in an hour.
-      if (isset($credentials['flood_control_user_identifier'])) {
-        flood_clear_event('failed_login_attempt_user', $credentials['flood_control_user_identifier']);
+    if (isset($credentials['flood_control_triggered'])) {
+      if ($credentials['flood_control_triggered'] == 'user') {
+        form_set_error('account_form][select][login][name', format_plural(variable_get('user_failed_login_user_limit', 5), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
+      }
+      else {
+        // We did not find a uid, so the limit is IP-based.
+        form_set_error('account_form][select][login][name', t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
       }
-      $form_state['commerce_checkout_login_uid'] = $credentials['uid'];
-      return TRUE;
     }
     else {
-      // Register events for flood control.
-      // Copied/adjusted from user_login_final_validate().
+      form_set_error('account_form][select][login][name', t('Sorry, unrecognized e-mail address or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password', array('query' => array('name' => $credentials['values']['mail']))))));
+      watchdog('commerce_checkout_login', 'Login attempt failed for %mail.', array('%mail' => $credentials['values']['mail']));
+    }
+  }
 
-      // Always register an IP-based failed login event.
-      flood_register_event('failed_login_attempt_ip', variable_get('user_failed_login_ip_window', 3600));
-      // Register a per-user failed login event.
-      if (isset($credentials['flood_control_user_identifier'])) {
-        flood_register_event('failed_login_attempt_user', variable_get('user_failed_login_user_window', 21600), $credentials['flood_control_user_identifier']);
-      }
+  // Display an appropriate error message if the user account is blocked.
+  if (user_is_blocked($account->name)) {
+    form_set_error('account_form][select][login][email', t('The username %name has not been activated or is blocked.', array('%name' => $account->name)));
+    return FALSE;
+  }
 
-      if (isset($credentials['flood_control_triggered'])) {
-        if ($credentials['flood_control_triggered'] == 'user') {
-          form_set_error('account][login][name', format_plural(variable_get('user_failed_login_user_limit', 5), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
-        }
-        else {
-          // We did not find a uid, so the limit is IP-based.
-          form_set_error('account][login][name', t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
-        }
-      }
-      else {
-        form_set_error('account][login][name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password', array('query' => array('name' => $credentials['values']['name']))))));
-        watchdog('commerce_checkout_login', 'Login attempt failed for %user.', array('%user' => $credentials['values']['name']));
-        return FALSE;
-      }
-    }
+  return FALSE;
+}
+
+/**
+ * Implements hook_commerce_checkout_complete().
+ */
+function commerce_checkout_login_commerce_checkout_complete($order) {
+  if (!empty($order->data['commerce_checkout_login_register'])) {
+    $username = $order->data['commerce_checkout_login_register']['username'];
+    $mail = $order->data['commerce_checkout_login_register']['mail'];
+    // Create account and login.
+    $account = commerce_checkout_create_account($username, $mail, user_password(), TRUE, TRUE);
+
+    $token = drupal_random_key();
+    $_SESSION['pass_reset_' . $account->uid] = $token;
+    $reset_link = l(t('Please set your password'), 'user/' . $account->uid . '/edit', array('query' => array('pass-reset-token' => $token)));
+    drupal_set_message(t('Your account has been created and you have been automatically logged in. !set_pass.', array('!set_pass' => $reset_link)));
+
+    // Send a notification email and inform the user about it.
+    _user_mail_notify('register_no_approval_required', $account);
+    drupal_set_message(t('A welcome message with further instructions has been sent to your e-mail address.'));
+
+    // Convert the order.
+    ccl_login_convert_order($account->uid, $order);
   }
 }
 
@@ -267,12 +190,11 @@ function _validate_existing_account(&$form, &$form_state, &$account) {
  *   The anonymous order to convert to an authenticated order.
  * @param $account
  *   The user account the order will belong to.
- *
- * @return
+ * @return bool|\EntityMetadataWrapper
  *   The updated order's wrapper or FALSE if the order was not converted,
- *     meaning it was not an anonymous cart order to begin with.
+ *   meaning it was not an anonymous cart order to begin with.
  */
-function commerce_checkout_login_order_convert($order, $account) {
+function ccl_order_convert($order, $account) {
   // Only convert orders that are currently anonymous.
   if ($order->uid == 0) {
     // Update the uid and e-mail address to match the current account since
@@ -305,11 +227,59 @@ function commerce_checkout_login_order_convert($order, $account) {
     }
 
     // Allow other modules to operate on the converted order and then save.
-    module_invoke_all('commerce_checkout_login_order_convert', $order_wrapper, $account);
+    module_invoke_all('ccl_order_convert', $order_wrapper, $account);
     $order_wrapper->save();
 
     return $order_wrapper;
   }
 
   return FALSE;
-}
\ No newline at end of file
+}
+
+/**
+ * Login user and convert his/her anonymous order.
+ */
+function ccl_login_convert_order($uid, $order) {
+  global $user;
+  // If the user was logged in during this request, make sure we are using the
+  // full user object.
+  if ($user->uid) {
+    $user = user_load($user->uid);
+  }
+  else {
+    // Load the validated user into the global $user variable.
+    $user = user_load($uid);
+
+    // "Finalize" the login by triggering the appropriate system messages, IP
+    // address and login timestamp logging, and user login hook.
+    user_login_finalize();
+  }
+
+  // Convert the current order from anonymous to authenticated and clear out
+  // our variable from the form state.
+  if (empty($order->uid)) {
+    ccl_order_convert($order, $user);
+  }
+}
+
+/**
+ *
+ */
+function ccl_account_information($order) {
+  $content[] = array(
+    '#type' => 'item',
+    '#markup' => t('%checkout', array('%checkout' => t('Your account will be created after completing checkout.'))),
+  );
+  $content[] = array(
+    '#type' => 'item',
+    '#title' => t('Username'),
+    '#markup' => check_plain($order->data['commerce_checkout_login_register']['username']),
+  );
+  $content[] = array(
+    '#type' => 'item',
+    '#title' => t('E-mail address'),
+    '#markup' => check_plain($order->data['commerce_checkout_login_register']['mail']),
+  );
+
+  return $content;
+}
diff --git a/commerce_checkout_login.panes.inc b/commerce_checkout_login.panes.inc
new file mode 100644
index 0000000..f55c625
--- /dev/null
+++ b/commerce_checkout_login.panes.inc
@@ -0,0 +1,234 @@
+<?php
+
+/**
+ * @file Contains all callbacks for Commerce checkout login's checkout panes.
+ */
+
+/**
+ * Account pane form callback.
+ */
+function commerce_checkout_login_account_form($form, &$form_state, $checkout_pane, $order) {
+  if ($form_state['account']->uid > 0) {
+    // The user is logged in, display account information.
+    module_load_include('inc', 'commerce_order', 'includes/commerce_order.checkout_pane');
+    $form['account_info']['#markup'] = commerce_order_account_pane_review($form, $form_state, $checkout_pane, $order);
+  }
+  else {
+
+    $replacements = array(
+      '%login' => t('Login & checkout'),
+      '%register' => t('Register & checkout'),
+      '%guest' => t('Checkout as guest')
+    );
+    $form['help']['#type'] = 'item';
+
+    if (variable_get('user_register', 0) && variable_get('commerce_checkout_login_allow_anonymous_checkout', TRUE)) {
+      // All forms of checkout are allowed.
+      $form['help']['#markup'] = t('If you have an existing account you can login by entering your login information in the form on the left and clicking the %login button. You can also create a new account by filling the form on the right and clicking the %register button or you can choose to skip account creation and checkout as a guest by clicking the %guest button at the bottom of the form.', $replacements);
+    }
+    elseif (variable_get('user_register', 0)) {
+      // Only login and register are allowed, guest checkout is disallowed.
+      $form['help']['#markup'] = t('If you have an existing account you can login by entering your login information in the form on the left and clicking the %login button or you can create a new account by filling the form on the right and clicking the %register button.', $replacements);
+    }
+    elseif (variable_get('commerce_checkout_login_allow_anonymous_checkout', TRUE)) {
+      // Only guest checkout and login are allowed, registration is disallowed.
+      $form['help']['#markup'] = t('If you have an existing account you can login by entering your login information in the form on the left and clicking the %login button or you can checkout as a guest by clicking the %guest button at the bottom of the form.', $replacements);
+    }
+    else {
+      // Only login is allowed, users are not allowed to perform guest checkout
+      // or create a new account themselves.
+      $form['help']['#markup'] = t('Please login to start the checkout process.', $replacements);
+    }
+
+    $form['select']['#type'] = 'container';
+
+    $form['select']['login'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Login'),
+    );
+
+    $form['select']['login']['mail'] = array(
+      '#type' => 'textfield',
+      '#title' => t('E-mail address'),
+      '#size' => 25,
+      '#required' => TRUE,
+    );
+
+    $form['select']['login']['password'] = array(
+      '#type' => 'password',
+      '#title' => t('Password'),
+      '#size' => 25,
+      '#required' => TRUE,
+    );
+
+    $form['select']['login']['continue'] = array(
+      '#type' => 'submit',
+      '#name' => 'login',
+      '#value' => t('Login & checkout'),
+      '#validate' => array('commerce_checkout_form_validate'),
+      '#limit_validation_errors' => array(
+        array(
+          'account_form',
+          'select',
+          'login'
+        )
+      ),
+      '#submit' => array('commerce_checkout_form_submit'),
+    );
+
+    // Only allow the user to register an account if they are allowed to do so.
+    if (variable_get('user_register', 0)) {
+      drupal_add_css(drupal_get_path('module', 'commerce_checkout_login') . '/css/commerce_checkout_login.admin.css');
+      $form['select']['register'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Register account'),
+      );
+
+      $form['select']['register']['username'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Username'),
+        '#size' => 25,
+        '#required' => TRUE,
+        '#default_value' => isset($order->data['commerce_checkout_login_register']['username']) ? $order->data['commerce_checkout_login_register']['username'] : '',
+        '#maxlength' => USERNAME_MAX_LENGTH,
+        '#description' => t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, apostrophes, and underscores.'),
+      );
+
+      $form['select']['register']['mail'] = array(
+        '#type' => 'textfield',
+        '#title' => t('E-mail address'),
+        '#default_value' => isset($order->data['commerce_checkout_login_register']['mail']) ? $order->data['commerce_checkout_login_register']['mail'] : '',
+        '#size' => 25,
+        '#description' => t('A valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.'),
+        '#required' => TRUE,
+      );
+
+      if (variable_get('commerce_order_account_pane_mail_double_entry', FALSE)) {
+        $form['select']['register']['mail_confirm'] = array(
+          '#type' => 'textfield',
+          '#title' => t('Confirm e-mail address'),
+          '#default_value' => isset($order->data['commerce_checkout_login_register']['mail']) ? $order->data['commerce_checkout_login_register']['mail'] : '',
+          '#size' => 25,
+          '#description' => t('Provide your e-mail address in both fields.'),
+          '#required' => TRUE,
+        );
+      }
+
+      $form['select']['register']['continue'] = array(
+        '#type' => 'submit',
+        '#name' => 'register',
+        '#value' => t('Register & checkout'),
+        '#validate' => array('commerce_checkout_form_validate'),
+        '#limit_validation_errors' => array(
+          array(
+            'account_form',
+            'select',
+            'register'
+          )
+        ),
+        '#submit' => array('commerce_checkout_form_submit'),
+      );
+    }
+
+  }
+
+  return $form;
+}
+
+/**
+ * Account pane validation handler.
+ */
+function  commerce_checkout_login_account_form_validate($form, &$form_state, $checkout_pane, $order) {
+  switch ($form_state['triggering_element']['#name']) {
+    case 'login':
+      // The login form was submitted.
+      $mail = trim($form_state['values']['account_form']['select']['login']['mail']);
+      if ($error = user_validate_mail($mail)) {
+        // An invalid e-mail address was entered.
+        form_set_error('account_form][select][login][mail', $error);
+      }
+      elseif ($account = user_load_by_mail($mail)) {
+        // A user can be loaded using the supplied email address. validate it.
+        return ccl_validate_existing_account($form, $form_state, $account);
+      }
+      elseif (!empty($form_state['values']['account_form']['select']['login']['password'])) {
+        // Only check non-existing e-mail addresses if a password was entered to
+        // prevent information disclosure.
+        form_set_error('account_form][select][login][mail', t('Sorry, unrecognized e-mail address or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password', array('query' => array('name' => $mail))))));
+      }
+      break;
+
+    case 'register':
+      // The register form was submitted, but we won't even consider validating
+      // the form it if no e-mail address was set.
+      if (isset($form_state['values']['account_form']['select']['register']['mail'])) {
+        $mail = trim($form_state['values']['account_form']['select']['register']['mail']);
+        if ($error = user_validate_mail($mail)) {
+          form_set_error('account_form][select][register][mail', $error);
+        }
+        elseif (isset($form_state['values']['account_form']['select']['register']['mail_confirm'])
+        && $form_state['values']['account_form']['select']['register']['mail_confirm'] !== $mail) {
+          form_set_error('account_form][select][register][mail', t('The specified e-mail addresses do not match.'));
+        }
+        elseif (!empty($form_state['values']['account_form']['select']['register']['username'])
+          && $account = user_load_by_mail($mail)) {
+          // Only validate the e-mail address if a username was supplied to
+          // prevent information disclosure.
+          form_set_error('account_form][select][register][mail', t('The e-mail address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array('%email' => $mail, '@password' => url('user/password'))));
+        }
+        elseif ($account = user_load_by_name($form_state['values']['account_form']['select']['register']['username'])) {
+          form_set_error('account_form][select][register][username', t('The name %name is already taken.', array('%name' => $form_state['values']['account_form']['select']['register']['username'])));
+        }
+        else{
+          return TRUE;
+        }
+      }
+      break;
+
+    case 'guest':
+      // Guest checkout does not need any validation.
+      return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+ * Account pane submit handler.
+ */
+function commerce_checkout_login_account_form_submit($form, &$form_state, $checkout_pane, $order) {
+  // commerce_checkout_login_uid gets set during ccl_validate_existing_account() if
+  // the account was validated successfully.
+  if (!empty($form_state['commerce_checkout_login_uid'])) {
+    ccl_login_convert_order($form_state['commerce_checkout_login_uid'], $order);
+    unset($form_state['commerce_checkout_login_uid']);
+  }
+  elseif (!empty($form_state['values']['account_form']['select']['register']['username'])
+    && !empty($form_state['values']['account_form']['select']['register']['mail'])
+  ) {
+    $order->data['commerce_checkout_login_register'] = $form_state['values']['account_form']['select']['register'];
+  }
+}
+
+/**
+ * Account pane settings form callback.
+ */
+function commerce_checkout_login_account_settings_form($checkout_pane) {
+  $form = array();
+
+  $form['commerce_checkout_login_allow_anonymous_checkout'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Allow anonymous checkout'),
+    '#description' => t('Checking this box allows anonymous users to checkout without creating a new account. Be sure to also disable the account creation rule defined by commerce.'),
+    '#default_value' => variable_get('commerce_checkout_login_allow_anonymous_checkout', TRUE),
+  );
+
+  $form['commerce_order_account_pane_mail_double_entry'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Require double entry of email address.'),
+    '#description' => t('Forces anonymous users to enter their email address in two consecutive fields, which must have identical values.') . '<br>' . t('This field uses the same setting as the account pane provided by Commerce Order'),
+    '#default_value' => variable_get('commerce_order_account_pane_mail_double_entry', FALSE),
+  );
+
+  return $form;
+}
diff --git a/css/commerce_checkout_login.admin.css b/css/commerce_checkout_login.admin.css
new file mode 100644
index 0000000..8e6aa92
--- /dev/null
+++ b/css/commerce_checkout_login.admin.css
@@ -0,0 +1,8 @@
+#edit-account-form-select{
+  display: flex;
+  justify-content: space-between;
+}
+
+#edit-account-form-select > .form-wrapper {
+  flex:0 0 49%;
+}
diff --git a/tests/CommerceCheckoutLoginTestBase.php b/tests/CommerceCheckoutLoginTestBase.php
new file mode 100644
index 0000000..8baa680
--- /dev/null
+++ b/tests/CommerceCheckoutLoginTestBase.php
@@ -0,0 +1,219 @@
+<?php
+
+/**
+ * @file
+ * Contains the test class for Commerce checkout login module tests.
+ */
+
+/**
+ * Class for commerce checkout login testing.
+ */
+abstract class CommerceCheckoutLoginTestBase extends CommerceBaseTestCase {
+
+  protected $currentOrder;
+  protected $lastInsertedUserId;
+  protected $siteAdministratorAccount;
+  protected $storeAdministratorAccount;
+  protected $storeCustomerAccount;
+  protected $testProduct;
+  protected $testProductNode;
+
+  /**
+   * Implementation of setUp().
+   */
+  function setUp() {
+    $modules = parent::setUpHelper('all', array('commerce_checkout_login'));
+    parent::setUp($modules);
+
+    // User creation for different operations.
+    $this->siteAdministratorAccount = $this->createSiteAdmin();
+    $this->storeAdministratorAccount = $this->createStoreAdmin();
+    $this->storeCustomerAccount = $this->createStoreCustomer();
+
+    // The rule that sends a mail after checkout completion should be disabled
+    // as it returns an error caused by how mail messages are stored.
+    $this->disableRule('commerce_checkout_order_email');
+  }
+
+  /**
+   * Helper function to prepare an anonymous enviroment, it sets the user,
+   *  products and prepares a cart.
+   */
+  protected function prepareAnonymousEnvironment() {
+    // Login as admin user to grant permissions.
+    $this->drupalLogin($this->siteAdministratorAccount);
+    $this->enablePermissionForRoles('access checkout', [
+      DRUPAL_ANONYMOUS_RID,
+      DRUPAL_AUTHENTICATED_RID
+    ]);
+
+    $this->createDummyProductDisplayContentType();
+    $this->testProduct = $this->createDummyProduct();
+    $this->testProductNode = $this->createDummyProductNode(array($this->testProduct->product_id), $this->randomName());
+
+    $this->ensureUserIsAnonymous();
+
+    // Submit the add to cart form.
+    $this->drupalPost('node/' . $this->testProductNode->nid, array(), t('Add to cart'));
+    $this->setCurrentOrder();
+
+    $this->lastInsertedUserId = $this->getLastAddedUserId();
+  }
+
+  /**
+   * @param $permission
+   * @param $role_ids
+   */
+  protected function enablePermissionForRoles($permission, array $role_ids) {
+    foreach ($role_ids as $rid) {
+      user_role_grant_permissions($rid, array($permission));
+    }
+  }
+
+  protected function ensureUserIsAnonymous() {
+    global $user;
+    $this->drupalLogout();
+    $user = user_load(0);
+  }
+
+  protected function setCurrentOrder() {
+    $orders = commerce_order_load_multiple(array(), array(
+      'uid' => 0,
+      'status' => 'cart'
+    ), TRUE);
+    $this->currentOrder = reset($orders);
+
+    entity_get_controller('commerce_order')->resetCache();
+  }
+
+  /**
+   * @return mixed
+   */
+  protected function getLastAddedUserId() {
+    return db_select('users')
+      ->fields('users', array())
+      ->orderBy('uid', 'DESC')
+      ->range(0, 1)
+      ->execute()
+      ->fetchCol();
+  }
+
+  /**
+   * Disables the account creation rule provided by commerce.
+   *
+   * This can be used to be able to ensure that commerce checkout login does not
+   * Create a new user account.
+   * @param $rule_id
+   */
+  protected function disableRule($rule_id) {
+    $rules_config = rules_config_load($rule_id);
+    $rules_config->active = FALSE;
+    $rules_config->save();
+  }
+
+  /**
+   * Generates some default form values for the checkout step.
+   * @return array
+   */
+  protected function generateAddressFormValues() {
+    $values = array(
+      'customer_profile_billing[commerce_customer_address][und][0][name_line]' => $this->randomName(),
+      'customer_profile_billing[commerce_customer_address][und][0][thoroughfare]' => $this->randomName(),
+      'customer_profile_billing[commerce_customer_address][und][0][premise]' => $this->randomName(),
+      'customer_profile_billing[commerce_customer_address][und][0][locality]' => $this->randomName(),
+    );
+
+    return $values;
+  }
+
+  /**
+   * @return bool
+   */
+  protected function userIsLoggedIn() {
+    $links = $this->xpath('//a[normalize-space(text())=:label]', array(':label' => t('Log out')));
+    return !empty($links);
+  }
+
+  /**
+   * @param string $username
+   */
+  protected function assertUsernameIsDisplayed($username) {
+    $this->assertText(t('Username'), 'Account information shows show the username label');
+    $this->assertText($username, 'Account information shows the username');
+  }
+
+  protected function noUsernameInformationDisplayed() {
+    $this->assertText(t('Username'), 'Account information does not show the username label');
+  }
+
+  /**
+   * @param string $email
+   */
+  protected function assertEmailAddressIsDisplayed($email) {
+    $this->assertText(t('E-mail address'), 'Account information shows the e-mail address label');
+    $this->assertText($email, 'Account information shows the e-mail address');
+  }
+
+  protected function assertNoNewAccountCreated() {
+    $this->assertEqual($this->lastInsertedUserId, $this->getLastAddedUserId(), 'No new account created');
+  }
+
+  protected function assertCheckoutWasCompletedWithoutCreatingNewAccount() {
+    $this->assertText(t('Checkout complete'));
+    $this->assertNoNewAccountCreated();
+  }
+
+  protected function startCheckoutProcess() {
+    $this->prepareAnonymousEnvironment();
+    $this->drupalPost('cart', array(), t('Checkout'));
+  }
+
+  /**
+   * @param $account
+   */
+  protected function assertAccountInformationIsDisplayedWithLabel($account) {
+    $this->assertText(t('Account information'), 'Account information is displayed.');
+    $this->assertAccountInformationIsDisplayed($account);
+  }
+
+  /**
+   * @param $account
+   */
+  protected function assertAccountInformationIsDisplayed($account) {
+    $this->assertEmailAddressIsDisplayed($account->mail);
+    $this->assertUsernameIsDisplayed($account->name);
+  }
+
+  protected function assertInvalidEmailMessageDisplayed($mail) {
+    $this->assertRaw(t('The e-mail address %mail is not valid.', array('%mail' => $mail)));
+  }
+
+  /**
+   * @param $form_values
+   */
+  protected function postContinue($form_values = array()) {
+    $this->drupalPost(NULL, $form_values, t('Continue to next step'));
+  }
+
+  protected function enableAccountInformationPane() {
+    variable_set('commerce_order_account_pane_auth_display', TRUE);
+  }
+
+  protected function disableAccountInformationPane() {
+    variable_set('commerce_order_account_pane_auth_display', FALSE);
+  }
+
+  protected function assertNoAccountInformationDisplayed() {
+    $this->assertNoText(t('Account information'), 'Account information is not displayed.');
+  }
+
+  protected function continueToReview($account) {
+    $this->postContinue($this->generateAddressFormValues());
+    $this->assertAccountInformationIsDisplayed($account);
+  }
+
+  protected function CompleteCheckout() {
+    $this->postContinue();
+  }
+
+}
diff --git a/tests/CommerceCheckoutLoginUserRegisterTest.test b/tests/CommerceCheckoutLoginUserRegisterTest.test
new file mode 100644
index 0000000..c553144
--- /dev/null
+++ b/tests/CommerceCheckoutLoginUserRegisterTest.test
@@ -0,0 +1,192 @@
+<?php
+
+/**
+ * Checkout register test class.
+ */
+class CommerceCheckoutLoginUserRegisterTest extends CommerceCheckoutLoginTestBase{
+
+  /**
+   * @return array
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Commerce checkout login User register',
+      'description' => 'Ensure users can register a new account during checkout.',
+      'group' => 'Drupal Commerce (Checkout login)',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp();
+    $this->startCheckoutProcess();
+  }
+
+  public function testInvalidEmailAddressIsRejected() {
+    $mail = 'invalid e-mail address';
+    $this->submitRegisterForm($this->randomName(), $mail);
+
+    $this->assertInvalidEmailMessageDisplayed($mail);
+  }
+
+  public function testDoubleEmailEntryValidation() {
+    $this->startCheckoutProcessWithDoubleMailEntry();
+
+    $mail = $this->generateEmail();
+    $this->submitRegisterFormWithConfirmedEmail($this->randomName(), $mail, $mail);
+
+    $this->assertNoRaw(t('The specified e-mail addresses do not match.'));
+  }
+
+  public function testDoubleEmailEntryValidationFails() {
+    $this->startCheckoutProcessWithDoubleMailEntry();
+
+    $this->submitRegisterFormWithConfirmedEmail($this->randomName(), $this->generateEmail(), $this->generateEmail());
+
+    $this->assertRaw(t('The specified e-mail addresses do not match.'));
+  }
+
+  public function testExistingUsernameIsDenied() {
+    $this->submitRegisterForm($this->storeCustomerAccount->name, $this->generateEmail());
+
+    $this->assertUsernameTakenMessageIsDisplayed($this->storeCustomerAccount->name);
+  }
+
+  public function testNoUsernameInformationLeakedWhenNoEmailAddressIsEntered() {
+    $this->submitRegisterForm($this->randomName(), '');
+//    $this->drupalPost(NULL, array('account_form[select][register][username]' => 'admin'), t('Register & checkout'));
+
+    $this->assertRaw(t('E-mail address field is required.'));
+    $this->assertNoUsernameTakenMessageIsDisplayed('admin');
+  }
+
+  public function testExistingEmailAddressIsDenied() {
+    $mail = $this->storeCustomerAccount->mail;
+    $this->submitRegisterForm($this->randomName(), $mail);
+    $this->assertEmailAddressAlreadyRegisteredMessageDisplayed($mail);
+  }
+
+  public function testNoEmailInformationLeakedWhenNoUsernameIsEntered() {
+    $mail = $this->storeCustomerAccount->mail;
+    $this->submitRegisterForm('', $mail);
+
+    $this->assertNoEmailAddressAlreadyRegisteredMessageDisplayed($mail);
+    $this->assertRaw(t('Username field is required.'));
+  }
+
+  public function testSuccessFullRegistrationAndCheckout() {
+    $userToRegister = $this->getValidUserToRegister();
+
+    $this->submitRegisterForm($userToRegister->name, $userToRegister->mail);
+    $this->assertNoNewAccountCreated();
+
+    $this->continueToReview($userToRegister);
+    $this->assertNoNewAccountCreated();
+
+    $this->CompleteCheckout();
+    $this->assertCheckoutCompletedWithNewAccount();
+  }
+
+  protected function testAccountInformationPaneCanBeEnabled() {
+    $this->enableAccountInformationPane();
+    $userToRegister = $this->getValidUserToRegister();
+
+    $this->submitRegisterForm($userToRegister->name, $userToRegister->mail);
+
+    $this->assertAccountInformationIsDisplayedWithLabel($userToRegister);
+  }
+
+  protected function testAccountInformationPaneCanBeDisabled() {
+    $this->disableAccountInformationPane();
+    $userToRegister = $this->getValidUserToRegister();
+
+    $this->submitRegisterForm($userToRegister->name, $userToRegister->mail);
+
+    $this->assertNoAccountInformationDisplayed();
+  }
+
+  /**
+   * @param string $user_name
+   * @param string $email
+   */
+  protected function submitRegisterForm($user_name, $email) {
+    $edit = array(
+      'account_form[select][register][username]' => $user_name,
+      'account_form[select][register][mail]' => $email,
+    );
+    $this->drupalPost(NULL, $edit, t('Register & checkout'));
+  }
+
+  protected function startCheckoutProcessWithDoubleMailEntry() {
+    $this->enableDoubleEmailEntry();
+    $this->startCheckoutProcess();
+  }
+
+  protected function enableDoubleEmailEntry() {
+    variable_set('commerce_order_account_pane_mail_double_entry', TRUE);
+  }
+
+  /**
+   * @param string $user_name
+   * @param string $email
+   * @param string $email_confirm
+   */
+  protected function submitRegisterFormWithConfirmedEmail($user_name, $email, $email_confirm) {
+    $edit = array(
+      'account_form[select][register][username]' => $user_name,
+      'account_form[select][register][mail]' => $email,
+      'account_form[select][register][mail_confirm]' => $email_confirm,
+    );
+    $this->drupalPost(NULL, $edit, t('Register & checkout'));
+  }
+
+  /**
+   * @param $name
+   */
+  protected function assertUsernameTakenMessageIsDisplayed($name) {
+    $this->assertRaw(t('The name %name is already taken.', array('%name' => $name)));
+  }
+
+  /**
+   * @param $name
+   */
+  protected function assertNoUsernameTakenMessageIsDisplayed($name) {
+    $this->assertNoRaw(t('The name %name is already taken.', array('%name' => $name)));
+  }
+
+  /**
+   * @param $mail
+   */
+  protected function assertEmailAddressAlreadyRegisteredMessageDisplayed($mail) {
+    $this->assertRaw(t('The e-mail address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array(
+      '%email' => $mail,
+      '@password' => url('user/password')
+    )));
+  }
+
+  /**
+   * @param $mail
+   */
+  protected function assertNoEmailAddressAlreadyRegisteredMessageDisplayed($mail) {
+    $this->assertNoRaw(t('The e-mail address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array(
+      '%email' => $mail,
+      '@password' => url('user/password')
+    )));
+  }
+
+  private function getValidUserToRegister() {
+    return (object) array(
+      'name' => $this->randomName(),
+      'mail' => $this->generateEmail(),
+    );
+  }
+
+  protected function assertNewAccountCreated() {
+    $this->assertNotEqual($this->lastInsertedUserId, $this->getLastAddedUserId(), 'New account created');
+  }
+
+  protected function assertCheckoutCompletedWithNewAccount() {
+    $this->assertText(t('Checkout complete'));
+    $this->assertNewAccountCreated();
+  }
+
+}
diff --git a/tests/commerceCheckoutLoginGuestCheckoutTest.test b/tests/commerceCheckoutLoginGuestCheckoutTest.test
new file mode 100644
index 0000000..001d052
--- /dev/null
+++ b/tests/commerceCheckoutLoginGuestCheckoutTest.test
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Contains tests for the Guest checkout functionality.
+ */
+
+/**
+ * Guest checkout test class.
+ */
+class CommerceCheckoutLoginGuestCheckoutTest extends CommerceCheckoutLoginTestBase {
+
+  /**
+   * @return array
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Commerce checkout login Guest checkout',
+      'description' => 'Ensure guests can checkout without having to register an account.',
+      'group' => 'Drupal Commerce (Checkout login)',
+    );
+  }
+
+  protected function testGuestCheckout() {
+    // Disable the account creation rule, since we want to make sure commerce
+    // checkout login does not create a new user during Guest checkout.
+    $this->disableRule('commerce_checkout_new_account');
+    $email = $this->generateEmail();
+
+    $this->startGuestCheckout();
+    $this->postGuestContactInformation($email);
+    $this->assertOnlyTheEmailAddressIsDisplayed($email);
+
+    $this->CompleteCheckout();
+    $this->assertCheckoutWasCompletedWithoutCreatingNewAccount();
+    $this->assertUserIsAnonymous();
+  }
+
+  protected function startGuestCheckout() {
+    $this->startCheckoutProcess();
+    $this->drupalPost(NULL, array(), t('Checkout as guest'));
+  }
+
+  /**
+   * @param string $email
+   */
+  protected function postGuestContactInformation($email) {
+    $edit = $this->generateAddressFormValues();
+    $edit['account[login][mail]'] = $email;
+    $this->postContinue($edit);
+  }
+
+  /**
+   * @param string $email
+   */
+  protected function assertOnlyTheEmailAddressIsDisplayed($email) {
+    $this->assertEmailAddressIsDisplayed($email);
+    $this->noUsernameInformationDisplayed();
+  }
+
+  protected function assertUserIsAnonymous() {
+    $this->assertFalse($this->userIsLoggedIn(), 'User is still anonymous');
+  }
+
+}
diff --git a/tests/commerceCheckoutLoginUserLoginTest.test b/tests/commerceCheckoutLoginUserLoginTest.test
new file mode 100644
index 0000000..2a0e1aa
--- /dev/null
+++ b/tests/commerceCheckoutLoginUserLoginTest.test
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * @file
+ * Contains tests for the user login functionality.
+ */
+
+/**
+ * Checkout login test class.
+ */
+class CommerceCheckoutLoginUserLoginTest extends CommerceCheckoutLoginTestBase {
+
+  /**
+   * @return array
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Commerce checkout login User login',
+      'description' => 'Ensure users with a pre-existing account can login during checkout.',
+      'group' => 'Drupal Commerce (Checkout login)',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->startCheckoutProcess();
+  }
+
+  protected function testInvalidEmailIsRejectedDuringLogin() {
+    $mail = 'invalid@email,test';
+    $this->postLoginForm($mail, $this->randomString());
+
+    $this->assertInvalidEmailMessageDisplayed($mail);
+  }
+
+  protected function testUnknownEmailIsRejectedDuringLogin() {
+    $mail = $this->generateEmail();
+    $this->postLoginForm($mail, $this->randomString());
+
+    $this->assertUnknownEmailOrPasswordMessage($mail);
+  }
+
+  protected function testUnknownPasswordIsRejectedDuringLogin() {
+    $mail = $this->storeCustomerAccount->mail;
+    $this->postLoginForm($mail, $this->randomString());
+    $this->assertUnknownEmailOrPasswordMessage($mail);
+  }
+
+  protected function testSuccessfulLoginAndCheckout() {
+    $this->postValidUserLogin();
+    $this->continueToReview($this->storeCustomerAccount);
+    $this->CompleteCheckout();
+
+    $this->assertCheckoutWasCompletedWithoutCreatingNewAccount();
+  }
+
+  protected function testAccountInformationPaneCanBeEnabled() {
+    $this->enableAccountInformationPane();
+
+    $this->postValidUserLogin();
+
+    $this->assertAccountInformationIsDisplayedWithLabel($this->storeCustomerAccount);
+  }
+
+  protected function testAccountInformationPaneCanBeDisabled() {
+    $this->disableAccountInformationPane();
+
+    $this->postValidUserLogin();
+
+    $this->assertNoAccountInformationDisplayed();
+  }
+
+  /**
+   * @param $mail
+   * @param $pass
+   */
+  protected function postLoginForm($mail, $pass) {
+    $edit = array(
+      'account_form[select][login][mail]' => $mail,
+      'account_form[select][login][password]' => $pass,
+    );
+    $this->drupalPost(NULL, $edit, t('Login & checkout'));
+  }
+
+  protected function postValidUserLogin() {
+    $this->postLoginForm($this->storeCustomerAccount->mail, $this->storeCustomerAccount->pass_raw);
+  }
+
+  /**
+   * @param $mail
+   */
+  protected function assertUnknownEmailOrPasswordMessage($mail) {
+    $replacement = array('@password' => url('user/password', array('query' => array('name' => $mail))));
+    $this->assertRaw(t('Sorry, unrecognized e-mail address or password. <a href="@password">Have you forgotten your password?</a>', $replacement));
+  }
+}
diff --git a/tests/commerce_checkout_login.test b/tests/commerce_checkout_login.test
deleted file mode 100644
index 943ec07..0000000
--- a/tests/commerce_checkout_login.test
+++ /dev/null
@@ -1,231 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains the test class for Commerce checkout login module tests.
- */
-
-/**
- * Class for commerce checkout login testing.
- */
-class CommerceCheckoutLoginTestCase extends CommerceBaseTestCase {
-
-  /**
-   * Order object.
-   */
-  protected $order;
-
-  /**
-   * The last inserted user id.
-   */
-  protected $last_uid;
-
-  /**
-   * The site administrator account.
-   */
-  protected $site_admin;
-
-  /**
-   * The store administrator account.
-   */
-  protected $store_admin;
-
-  /**
-   * The customer account.
-   */
-  protected $store_customer;
-
-  /**
-   * Provide info about this test.
-   *
-   * @return array
-   */
-  public static function getInfo() {
-    return array(
-      'name' => 'Commerce checkout login',
-      'description' => 'Ensure commerce checkout login behaves as expected',
-      'group' => 'Drupal Commerce',
-    );
-  }
-
-  /**
-   * Implementation of setUp().
-   */
-  function setUp() {
-    $modules = parent::setUpHelper('all', array('commerce_checkout_login'));
-    parent::setUp($modules);
-
-    // User creation for different operations.
-    $this->site_admin = $this->createSiteAdmin();
-    $this->store_admin = $this->createStoreAdmin();
-    $this->store_customer = $this->createStoreCustomer();
-
-    // The rule that sends a mail after checkout completion should be disabled
-    //  as it returns an error caused by how mail messages are stored.
-    $rules_config = rules_config_load('commerce_checkout_order_email');
-    $rules_config->active = FALSE;
-    $rules_config->save();
-  }
-
-  /**
-   * Helper function to prepare an anonymous enviroment, it sets the user,
-   *  products and prepares a cart.
-   */
-  protected function prepareAnonymousEnviroment() {
-    // Login as admin user to grant permissions.
-    $this->drupalLogin($this->site_admin);
-    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
-      'access checkout' => TRUE,
-    ));
-
-    // Create a dummy product display content type.
-    $this->createDummyProductDisplayContentType();
-    // Create dummy product display nodes (and their corresponding product
-    //  entities).
-    $this->product = $this->createDummyProduct();
-    $this->product_node = $this->createDummyProductNode(array($this->product->product_id), $this->randomName());
-
-    // Logout to test the checkout process with anonymous user.
-    $this->drupalLogout();
-
-    // Override user variable to get the environment fully set.
-    global $user;
-    $user = user_load(0);
-
-    // Submit the add to cart form.
-    $this->drupalPost('node/' . $this->product_node->nid, array(), t('Add to cart'));
-
-    // Get the order for the anonymous user.
-    $orders = commerce_order_load_multiple(array(), array(
-      'uid' => $user->uid,
-      'status' => 'cart'
-    ), TRUE);
-    $this->order = reset($orders);
-    // Reset the cache as we don't want to keep the lock.
-    entity_get_controller('commerce_order')->resetCache();
-
-    $this->last_uid = $this->getLastUid();
-  }
-
-  /**
-   * Test the checkout process for anonymous users without creating new account.
-   */
-  protected function testAnonymousCheckout() {
-    $this->prepareAnonymousEnviroment();
-    // Disable the account creation rule, since we want to make sure commerce
-    // checkout login does not create a new user.
-    $this->disableAccountCreationRule();
-
-    // Start checkout
-    $this->drupalPost('cart', array(), t('Checkout'));
-    $edit = $this->generateAddressFormValues();
-    $edit['account[login][mail]'] = $this->generateEmail();
-    $this->drupalPost("checkout/{$this->order->order_id}", $edit, t('Continue to next step'));
-    $this->continueCheckout();
-    $this->assertEqual($this->last_uid, $this->getLastUid(), 'No new account created');
-    $this->assertFalse($this->userLoggedIn(), 'User is still anonymous');
-  }
-
-  /**
-   * Test checkout process for user logging in during checkout.
-   */
-  protected function testCheckoutLogin() {
-    $this->prepareAnonymousEnviroment();
-    // Disable the account creation rule, since we want to make sure commerce
-    // checkout login does not create a new user.
-    $this->disableAccountCreationRule();
-
-    // Start checkout
-    $this->drupalPost('cart', array(), t('Checkout'));
-    $edit = $this->generateAddressFormValues();
-    $edit['account[login][mail]'] = $this->store_customer->mail;
-    $this->drupalPost("checkout/{$this->order->order_id}", $edit, t('Continue to next step'));
-    $this->assertRaw(t('There is already an account registered to %mail. Please enter your password to continue checkout.', array('%mail' => $this->store_customer->mail)));
-    $this->assertFieldByName('account[login][password]');
-    $this->drupalPost(NULL, array('account[login][password]' => $this->store_customer->pass_raw), t('Continue to next step'));
-    $this->assertTrue($this->userLoggedIn(), 'User is logged in');
-    $this->continueCheckout();
-    $this->assertEqual($this->last_uid, $this->getLastUid(), 'No new account created');
-  }
-
-  /**
-   * Test AJAX checkout process for user logging in during checkout.
-   */
-  protected function testAJAXCheckoutLogin() {
-    $this->prepareAnonymousEnviroment();
-    // Disable the account creation rule, since we want to make sure commerce
-    // checkout login does not create a new user.
-    $this->disableAccountCreationRule();
-
-    // Start checkout
-    $this->drupalPost('cart', array(), t('Checkout'));
-    $edit['account[login][mail]'] = $this->store_customer->mail;
-    $this->drupalPostAJAX("checkout/{$this->order->order_id}", $edit, 'account[login][mail]');
-    $this->assertFieldByName('account[login][password]');
-    $edit = $this->generateAddressFormValues();
-    $edit['account[login][password]'] = $this->store_customer->pass_raw;
-    $this->drupalPost(NULL, $edit, t('Continue to next step'));
-    $this->assertTrue($this->userLoggedIn(), 'User is logged in');
-    $this->continueCheckout();
-    $this->assertEqual($this->last_uid, $this->getLastUid(), 'No new account created');
-  }
-
-  /**
-   * Disables the account creation rule provided by commerce.
-   *
-   * This can be used to be able to ensure that commerce checkout login does not
-   * Create a new user account.
-   */
-  protected function disableAccountCreationRule() {
-    $rules_config = rules_config_load('commerce_checkout_new_account');
-    $rules_config->active = FALSE;
-    $rules_config->save();
-  }
-
-  /**
-   * Continues checkout after the authentication is done.
-   */
-  protected function continueCheckout() {
-    $this->assertUrl("checkout/{$this->order->order_id}/review", array(), 'Checkout proceeded to the review step');
-    $this->drupalPost(NULL, array(), t('Continue to next step'));
-  }
-
-  /**
-   * Generates some default form values for the checkout step.
-   * @return array
-   */
-  protected function generateAddressFormValues() {
-    $values = array(
-      'customer_profile_billing[commerce_customer_address][und][0][name_line]' => $this->randomName(),
-      'customer_profile_billing[commerce_customer_address][und][0][thoroughfare]' => $this->randomName(),
-      'customer_profile_billing[commerce_customer_address][und][0][premise]' => $this->randomName(),
-      'customer_profile_billing[commerce_customer_address][und][0][locality]' => $this->randomName(),
-    );
-
-    return $values;
-  }
-
-  /**
-   * retrieves the last added user id.
-   * @return mixed
-   */
-  protected function getLastUid() {
-    return db_select('users')
-      ->fields('users', array())
-      ->orderBy('uid', 'DESC')
-      ->range(0, 1)
-      ->execute()
-      ->fetchCol();
-  }
-
-  /**
-   * Determines if a user is logged in.
-   *
-   * @return bool
-   */
-  protected function userLoggedIn() {
-    $links = $this->xpath('//a[normalize-space(text())=:label]', array(':label' => t('Log out')));
-    return !empty($links);
-  }
-
-}
