You are here

commerce_cart.test in Commerce Core 7

Functional tests for the commerce cart module.

File

modules/cart/tests/commerce_cart.test
View source
<?php

/**
 * @file
 * Functional tests for the commerce cart module.
 */

/**
 * Abstract class for Commerce cart testing. All Commerce cart tests should
 * extend this class.
 */
abstract class CommerceCartTestCase extends CommerceBaseTestCase {

  /**
   * Helper function to  perform the common test tasks for cart testing.
   * @see CommerceBaseTestCase::setUpHelper()
   */
  protected function setUpHelper($set = 'all', array $other_modules = array()) {
    $modules = parent::setUpHelper($set, $other_modules);
    parent::setUp($modules);
    $this->store_admin = $this
      ->createStoreAdmin();
    $this->store_customer = $this
      ->createStoreCustomer();
  }

}

/**
 * Test cart features for a product display that only has one product attached.
 */
class CommerceCartTestCaseSimpleProduct extends CommerceCartTestCase {

  /**
   * Product that is being added to the cart.
   */
  protected $product;

  /**
   * Product display.
   */
  protected $product_node;

  /**
   * Implementation of getInfo().
   */
  public static function getInfo() {
    return array(
      'name' => 'Shopping cart',
      'description' => 'Test cart features like adding products to the cart, removing products from the cart and updating quantities.',
      'group' => 'Drupal Commerce',
    );
  }

  /**
   * Implementation of setUp().
   */
  function setUp() {
    parent::setUpHelper('all');

    // Create a dummy product display content type.
    $this
      ->createDummyProductDisplayContentType();

    // Create dummy product display nodes (and their corresponding product
    //  entities).
    $sku = 'PROD-01';
    $product_name = 'Product One';
    $this->product = $this
      ->createDummyProduct($sku, $product_name);
    $this->product_node = $this
      ->createDummyProductNode(array(
      $this->product->product_id,
    ), $product_name);

    // Log as a normal user to test cart process.
    $this
      ->drupalLogin($this->store_customer);

    // Submit the add to cart form.
    $this
      ->drupalPost('node/' . $this->product_node->nid, array(), t('Add to cart'));
  }

  /**
   * Test if the product form has the correct structure.
   */
  public function testCommerceCartProductFormStructure() {

    // Go to cart url.
    $this
      ->drupalGet('node/' . $this->product_node->nid);
    $this
      ->assertField('edit-submit', t('Add to cart button exists'));
  }

  /**
   * Test if the product has been correctly added to the cart.
   */
  public function testCommerceCartAdd() {

    // Ensure the add to cart message is displayed.
    $message = t('%title added to <a href="!cart-url">your cart</a>.', array(
      '%title' => $this->product_node->title,
      '!cart-url' => url('cart'),
    ));
    $this
      ->assertRaw($message, t('Product add to cart message displayed.'));

    // Go to cart url.
    $this
      ->drupalGet($this
      ->getCommerceUrl('cart'));

    // Test if the page resolves and there is something in the cart.
    $this
      ->assertResponse(200);
    $this
      ->assertNoText(t('Your shopping cart is empty.'), t('Cart is not empty'));
    $this
      ->assertText($this->product->title, t('Product was added to the cart'));
  }

  /**
   * Test if the cart form has the correct fields and structure.
   */
  public function testCommerceCartFormStructure() {

    // Check if the form is present and it has the quantity field, remove and
    //  submit buttons.
    // Go to cart url.
    $this
      ->drupalGet($this
      ->getCommerceUrl('cart'));

    // Check remove button.
    $this
      ->assertFieldByXPath("//input[starts-with(@id, 'edit-edit-delete')]", NULL, t('Remove button present'));

    // Check quantity field.
    $this
      ->assertFieldByXPath("//input[starts-with(@id, 'edit-edit-quantity')]", NULL, t('Quantity field present'));
    $this
      ->assertFieldByXPath("//input[starts-with(@id, 'edit-edit-quantity')]", 1, t('Quantity field has correct number of items'));

    // Check if the Update cart and Checkout buttons are present.
    $this
      ->assertField("edit-submit", t('Update cart button present'));
    $this
      ->assertField("edit-checkout", t('Checkout button present'));
  }

  /**
   * Test if the product is present in the order stored in db.
   */
  public function testCommerceCartOrder() {

    // Load the current order of the user.
    $order = commerce_cart_order_load($this->store_customer->uid);
    $products = array();
    $this
      ->assertTrue(commerce_cart_order_is_cart($order), t('User has currently an order in cart status.'));

    // Get the products out of the order and store them in an array.
    foreach (entity_metadata_wrapper('commerce_order', $order)->commerce_line_items as $delta => $line_item_wrapper) {
      if (in_array($line_item_wrapper
        ->getBundle(), commerce_product_line_item_types())) {
        $product = $line_item_wrapper->commerce_product
          ->value();
        $products[$product->product_id] = $product;
      }
    }

    // Check if the product is in the products array for the order.
    $this
      ->assertTrue(array_key_exists($this->product->product_id, $products), t('Product is actually in the cart'));
  }

  /**
   * Test the quantity changes in the cart.
   */
  public function testCommerceCartChangeQty() {

    // Go to cart url.
    $this
      ->drupalGet($this
      ->getCommerceUrl('cart'));

    // Change quantity in the cart view form.
    // We search for the first quantity field in the html and change the
    //   amount there.
    $qty = $this
      ->xpath("//input[starts-with(@name, 'edit_quantity')]");
    $this
      ->drupalPost($this
      ->getCommerceUrl('cart'), array(
      (string) $qty[0]['name'] => 2,
    ), t('Update cart'));

    // Check if the amount has been really changed.
    $this
      ->assertFieldByXPath("//input[starts-with(@id, 'edit-edit-quantity')]", 2, t('Cart updated with new quantity'));
  }

  /**
   * Test removing a product from the cart.
   */
  public function testCommerceCartRemove() {

    // Go to cart url.
    $this
      ->drupalGet($this
      ->getCommerceUrl('cart'));

    // Remove the product from the cart.
    $this
      ->drupalPost(NULL, array(), t('Remove'));

    // Test if the page resolves and there is something in the cart.
    $this
      ->assertText(t('Your shopping cart is empty.'), t('Removed product and cart is empty'));
  }

}

/**
 * Test cart features for a product display that has several products attached.
 */
class CommerceCartTestCaseMultiProducts extends CommerceCartTestCase {

  /**
   * Products that are being added to the cart.
   */
  protected $products = array();

  /**
   * Titles of the products that are being added to the cart.
   */
  protected $product_titles = array();

  /**
   * Product display.
   */
  protected $product_node;

  /**
   * Implementation of getInfo().
   */
  public static function getInfo() {
    return array(
      'name' => 'Shopping cart multiple',
      'description' => 'Test adding products to cart from a product display node with multiple products, using the product select add to cart form.',
      'group' => 'Drupal Commerce',
    );
  }

  /**
   * Implementation of setUp().
   */
  function setUp() {
    parent::setUpHelper('all');

    // Create a dummy product display content type.
    $this
      ->createDummyProductDisplayContentType('product_display', TRUE, 'field_product', 2);

    // Create dummy product display nodes (and their corresponding product
    //  entities).
    $products = array();
    $sku = 'PROD-01';
    $product_name = 'Product One';
    $this->product_titles[] = $product_name;
    $product = $this
      ->createDummyProduct($sku, $product_name);
    $this->products[$product->product_id] = $product;
    $sku = 'PROD-02';
    $product_name = 'Product Two';
    $this->product_titles[] = $product_name;
    $product = $this
      ->createDummyProduct($sku, $product_name);
    $this->products[$product->product_id] = $product;
    $this->product_node = $this
      ->createDummyProductNode(array_keys($this->products), 'Combined Product');

    // Log as a normal user to test cart process.
    $this
      ->drupalLogin($this->store_customer);

    // Submit the add to cart form.
    $this
      ->drupalPost('node/' . $this->product_node->nid, array(
      'product_id' => $this->products[2]->product_id,
    ), t('Add to cart'));
  }

  /**
   * Test the structure of the product form.
   */
  public function testCommerceCartProductFormStructure() {
    $option_titles = array();

    // Get the options of the product's select.
    $options = $this
      ->xpath("//select[@id='edit-product-id']//option");
    foreach ($options as $option) {
      $option_titles[] = (string) $option;
    }

    // Check if the selector exists.
    $this
      ->assertField('edit-product-id', t('The selector of products exists'));

    // Check if the products actually are present in the selector.
    $this
      ->assertTrue($this->product_titles == $option_titles, t('Correct products are present in the selector'));

    // Look for the Add to cart button.
    $this
      ->assertField('edit-submit', t('Add to cart button exists'));
  }

  /**
   * Test to select one product and check if it has been correctly added to
   *  the cart.
   */
  public function testCommerceCartSelectProductAdd() {

    // Ensure the add to cart message is displayed.
    $message = t('%title added to <a href="!cart-url">your cart</a>.', array(
      '%title' => $this->product_titles[1],
      '!cart-url' => url('cart'),
    ));
    $this
      ->assertRaw($message, t('Product add to cart message displayed.'));

    // Go to cart url.
    $this
      ->drupalGet($this
      ->getCommerceUrl('cart'));

    // Test if the page resolves and there is something in the cart.
    $this
      ->assertResponse(200);
    $this
      ->assertNoText(t('Your shopping cart is empty.'), t('Cart is not empty'));
    $this
      ->assertText($this->product_titles[1], t('Product was added to the cart'));
  }

  /**
   * Test if the cart form has the correct fields and structure.
   */
  public function testCommerceCartFormStructure() {

    // Check if the form is present and it has the quantity field, remove and
    //  submit buttons.
    // Go to cart url.
    $this
      ->drupalGet($this
      ->getCommerceUrl('cart'));

    // Check remove button.
    $this
      ->assertFieldByXPath("//input[starts-with(@id, 'edit-edit-delete')]", NULL, t('Remove button present'));

    // Check quantity field.
    $this
      ->assertFieldByXPath("//input[starts-with(@id, 'edit-edit-quantity')]", NULL, t('Quantity field present'));
    $this
      ->assertFieldByXPath("//input[starts-with(@id, 'edit-edit-quantity')]", 1, t('Quantity field has correct number of items'));

    // Check if the Update cart and Checkout buttons are present.
    $this
      ->assertField("edit-submit", t('Update cart button present'));
    $this
      ->assertField("edit-checkout", t('Checkout button present'));
  }

  /**
   * Test if the product is present in the order stored in db.
   */
  public function testCommerceCartOrder() {
    $products_in_cart = array();

    // Load the current order of the user.
    $order = commerce_cart_order_load($this->store_customer->uid);

    // Check if the user has at least one order in cart status.
    $this
      ->assertTrue(commerce_cart_order_is_cart($order), t('User has currently an order in cart status.'));

    // Get the products out of the order and store them in an array.
    foreach (entity_metadata_wrapper('commerce_order', $order)->commerce_line_items as $delta => $line_item_wrapper) {
      if (in_array($line_item_wrapper
        ->getBundle(), commerce_product_line_item_types())) {
        $product = $line_item_wrapper->commerce_product
          ->value();
        $products_in_cart[$product->product_id] = $product;
      }
    }

    // Check if the product is in the products array for the order.
    $this
      ->assertTrue(array_key_exists($this->products[2]->product_id, $products_in_cart), t('Product is actually in the cart'));
  }

}

/**
 * Test cart features for a product with attributes.
 */
class CommerceCartTestCaseAttributes extends CommerceCartTestCase {

  /**
   * Products that are being added to the cart.
   */
  protected $products = array();

  /**
   * Product display.
   */
  protected $product_node;

  /**
   * Implementation of getInfo().
   */
  public static function getInfo() {
    return array(
      'name' => 'Shopping cart attributes',
      'description' => 'Test adding products to cart from a product with multiple attributes, using the add to cart form product attribute select.',
      'group' => 'Drupal Commerce',
    );
  }

  /**
   * Implementation of setUp().
   */
  function setUp() {
    parent::setUpHelper('all');

    // Create a dummy product display content type.
    $this
      ->createDummyProductDisplayContentType('product_display', TRUE, 'field_product', FIELD_CARDINALITY_UNLIMITED);

    // Create the fields and bind them to the product.
    $this->fields['field_1'] = array(
      'field_name' => 'field_1',
      'type' => 'list_text',
      'cardinality' => 1,
      'settings' => array(
        'allowed_values' => array(
          'field_1_value_1' => 'field_1_value_1',
          'field_1_value_2' => 'field_1_value_2',
        ),
      ),
    );
    $this->fields['field_1'] = field_create_field($this->fields['field_1']);
    $this->fields['field_2'] = array(
      'field_name' => 'field_2',
      'type' => 'list_text',
      'cardinality' => 1,
      'settings' => array(
        'allowed_values' => array(
          'field_2_value_1' => 'field_2_value_1',
          'field_2_value_2' => 'field_2_value_2',
        ),
      ),
    );
    $this->fields['field_2'] = field_create_field($this->fields['field_2']);
    foreach ($this->fields as $field) {
      $instance = array(
        'field_name' => $field['field_name'],
        'entity_type' => 'commerce_product',
        'bundle' => 'product',
        'label' => $field['field_name'] . '_label',
        'description' => $field['field_name'] . '_description',
        'required' => TRUE,
        'widget' => array(
          'module' => 'options',
          'type' => 'options_select',
        ),
        'commerce_cart_settings' => array(
          'attribute_field' => TRUE,
          'attribute_widget' => 'select',
        ),
      );
      field_create_instance($instance);
    }

    // Populate the different values for the fields and create products.
    foreach ($this->fields['field_1']['settings']['allowed_values'] as $field_1_value) {
      foreach ($this->fields['field_2']['settings']['allowed_values'] as $field_2_value) {
        $product = $this
          ->createDummyProduct('PROD-' . $field_1_value . '-' . $field_2_value, $field_1_value . '_' . $field_2_value);
        $product->field_1[LANGUAGE_NONE][0]['value'] = $field_1_value;
        $product->field_2[LANGUAGE_NONE][0]['value'] = $field_2_value;
        $product->is_new = FALSE;
        commerce_product_save($product);
        $this->products[$product->product_id] = $product;
      }
    }

    // Create dummy product display node.
    $this->product_node = $this
      ->createDummyProductNode(array_keys($this->products), 'Combined Product');

    // Log as a normal user to test cart process.
    $this
      ->drupalLogin($this->store_customer);
  }

  /**
   * Test the add to cart functional process with attributes.
   */
  public function testCommerceCartSelectProductAdd() {

    // Go to product page.
    $this
      ->drupalGet('node/' . $this->product_node->nid);

    // Set the product that we are checking.
    $product_wrapper = entity_metadata_wrapper('commerce_product', $this->products[3]);

    // Select one of the attributes.
    $this
      ->drupalPostAJAX(NULL, array(
      'attributes[field_1]' => $product_wrapper->field_1
        ->value(),
    ), 'attributes[field_1]');

    // Add product to the cart.
    $this
      ->drupalPost(NULL, array(), t('Add to cart'));

    // Ensure the add to cart message is displayed.
    $message = t('%title added to <a href="!cart-url">your cart</a>.', array(
      '%title' => 'field_1_value_2_field_2_value_1',
      '!cart-url' => url('cart'),
    ));
    $this
      ->assertRaw($message, t('Product add to cart message displayed.'));

    // Go to cart url.
    $this
      ->drupalGet($this
      ->getCommerceUrl('cart'));

    // Test if the page resolves and there is something in the cart.
    $this
      ->assertResponse(200);
    $this
      ->assertNoText(t('Your shopping cart is empty.'), t('Cart is not empty'));
    $this
      ->assertText('field_1_value_2_field_2_value_1', t('Product was added to the cart'));
  }

  /**
   * Test the form structure of the Product.
   */
  public function testCommerceCartProductFormStructure() {
    $this
      ->drupalGet('node/' . $this->product_node->nid);

    // Check whether the attribute selectors exist.
    $this
      ->assertField('edit-attributes-field-1', t('First attribute selector exists'));
    $this
      ->assertField('edit-attributes-field-2', t('Second attribute selector exists'));

    // Check the number of attributes.
    $options = $this
      ->xpath("//select[@id='edit-attributes-field-1']//option");
    $this
      ->assertEqual(count($options), count($this->fields['field_1']['settings']['allowed_values']), t('Number of options for first attribute match'));
    $options = $this
      ->xpath("//select[@id='edit-attributes-field-2']//option");
    $this
      ->assertEqual(count($options), count($this->fields['field_2']['settings']['allowed_values']), t('Number of options for second attribute match'));

    // Look for the Add to cart button.
    $this
      ->assertField('edit-submit', t('Add to cart button exists'));
  }

}

/**
 * Test cart conversion from anonymous to authenticated.
 */
class CommerceCartTestCaseAnonymousToAuthenticated extends CommerceCartTestCase {

  /**
   * Product that is being added to the cart.
   */
  protected $product;

  /**
   * Product display.
   */
  protected $product_node;

  /**
   * Implementation of getInfo().
   */
  public static function getInfo() {
    return array(
      'name' => 'Shopping cart anonymous to authenticated',
      'description' => 'Test cart conversion from anonymous to authenticated when an anonymous users logs in.',
      'group' => 'Drupal Commerce',
    );
  }

  /**
   * Implementation of setUp().
   */
  function setUp() {
    parent::setUpHelper('all');

    // Create a dummy product display content type.
    $this
      ->createDummyProductDisplayContentType();

    // Create dummy product display nodes (and their corresponding product
    //  display).
    $sku = 'PROD-01';
    $product_name = 'Product One';
    $this->product = $this
      ->createDummyProduct($sku, $product_name);
    $this->product_node = $this
      ->createDummyProductNode(array(
      $this->product->product_id,
    ), $product_name);
  }

  /**
   * Test anonymous cart conversion.
   */
  public function testCommerceCartAnonymousToAuthenticated() {

    // Logout to be anonymous and force user uid.
    $this
      ->drupalLogout();
    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 just created.
    $orders = commerce_order_load_multiple(array(), array(
      'uid' => $user->uid,
      'status' => 'cart',
    ), TRUE);
    $order_anonymous = reset($orders);

    // Reset the cache as we don't want to keep the lock.
    entity_get_controller('commerce_order')
      ->resetCache();

    // Access to the cart and check if the product is in it.
    $this
      ->drupalGet($this
      ->getCommerceUrl('cart'));
    $this
      ->assertNoText(t('Your shopping cart is empty.'), t('Cart is not empty'));
    $this
      ->assertText($this->product->title, t('Product was added to the cart'));

    // Change the price to check if the amount gets updated when the user logs
    // in.
    $new_price = $this->product->commerce_price[LANGUAGE_NONE][0]['amount'] + rand(2, 500);
    $this->product->commerce_price[LANGUAGE_NONE][0]['amount'] = $new_price;
    $this->product->is_new = FALSE;
    commerce_product_save($this->product);

    // Log in with normal user.
    $this
      ->drupalPost('user', array(
      'name' => $this->store_customer->name,
      'pass' => $this->store_customer->pass_raw,
    ), t('Log in'));

    // Get the order for user just logged in.
    $orders = commerce_order_load_multiple(array(), array(
      'uid' => $this->store_customer->uid,
      'status' => 'cart',
    ), TRUE);
    $order_authenticated = reset($orders);

    // Reset the cache as we don't want to keep the lock.
    entity_get_controller('commerce_order')
      ->resetCache();

    // Access to the cart and check if the product is in it.
    $this
      ->drupalGet($this
      ->getCommerceUrl('cart'));
    $this
      ->assertNoText(t('Your shopping cart is empty.'), t('Cart is not empty'));
    $this
      ->assertText($this->product->title, t('Product is still in the cart'));
    $this
      ->assertText(trim(commerce_currency_amount_to_decimal($this->product->commerce_price[LANGUAGE_NONE][0]['amount'], $this->product->commerce_price[LANGUAGE_NONE][0]['currency_code'])), t('Product price has been updated'));

    // Check if the order is the same.
    $this
      ->assertTrue($order_anonymous->order_id == $order_authenticated->order_id, t('Cart has been converted successfully'));
  }

}

Classes

Namesort descending Description
CommerceCartTestCase Abstract class for Commerce cart testing. All Commerce cart tests should extend this class.
CommerceCartTestCaseAnonymousToAuthenticated Test cart conversion from anonymous to authenticated.
CommerceCartTestCaseAttributes Test cart features for a product with attributes.
CommerceCartTestCaseMultiProducts Test cart features for a product display that has several products attached.
CommerceCartTestCaseSimpleProduct Test cart features for a product display that only has one product attached.