๐Ÿ”ฅ 0
โญ 0
Lesson 7 of 10 30 min +250 XP

Testing the Shopping Cart

Why Cart Testing Matters

The shopping cart is revenue-critical. Cart bugs directly impact:

  • Conversion rates
  • Customer trust
  • Revenue accuracy
  • Inventory management

> "A bug in the checkout flow costs you money. A bug in the About page costs you almost nothing."

Cart Test Categories

Cart Testing Priority

Prioritize your cart testing efforts based on risk and impact:

CRITICAL (Must automate): Add to cart, remove, update quantity, total calculation, proceed to checkout IMPORTANT (Should automate): Cart persistence, out of stock handling, max quantity limits, guest vs logged-in, promo codes NICE TO HAVE (Manual or selective): Cart animations, cross-sell suggestions, save for later

Test Cases: Add to Cart

# tests/test_add_to_cart.py
import pytest
from pages.products_page import ProductsPage
from pages.components.header import Header

class TestAddToCart:

    def test_add_single_product(self, driver):
        """
        Given: User is on products page
        When: User clicks Add to Cart on a product
        Then: Cart count increases by 1
        """
        products = ProductsPage(driver).open()
        header = Header(driver)

        initial_count = header.get_cart_count()
        products.add_product_to_cart(0)

        assert header.get_cart_count() == initial_count + 1

    def test_add_multiple_different_products(self, driver):
        """
        Given: User adds Product A to cart
        When: User adds Product B to cart
        Then: Cart shows 2 items
        """
        products = ProductsPage(driver).open()
        header = Header(driver)

        products.add_product_to_cart(0)
        products.add_product_to_cart(1)

        assert header.get_cart_count() == 2

    def test_add_same_product_twice(self, driver):
        """
        Given: User adds Product A to cart
        When: User adds Product A again
        Then: Cart shows 1 item with quantity 2
        """
        products = ProductsPage(driver).open()

        products.add_product_to_cart(0)
        products.add_product_to_cart(0)  # Same product

        cart = Header(driver).go_to_cart()
        assert cart.get_item_count() == 1
        assert cart.get_item_by_index(0).quantity == 2

    def test_add_to_cart_shows_confirmation(self, driver):
        """
        Given: User clicks Add to Cart
        Then: Confirmation message appears
        And: Confirmation disappears after a few seconds
        """
        products = ProductsPage(driver).open()

        products.add_product_to_cart(0)

        # Check confirmation appears
        assert products.is_visible(products.ADD_CONFIRMATION)

        # Check it disappears (wait up to 5 seconds)
        from selenium.webdriver.support.ui import WebDriverWait
        from selenium.webdriver.support import expected_conditions as EC
        WebDriverWait(driver, 5).until(
            EC.invisibility_of_element_located(products.ADD_CONFIRMATION)
        )

    def test_add_to_cart_button_state_change(self, driver):
        """
        Given: User adds product to cart
        Then: Button changes to "Added" or shows checkmark
        """
        products = ProductsPage(driver).open()
        product = products.get_product_by_index(0)

        # Get button before
        add_btn = product.find_element(*products.ADD_TO_CART_BTN)
        original_text = add_btn.text

        products.add_product_to_cart(0)

        # Button should change
        new_text = add_btn.text
        assert new_text != original_text or "Added" in new_text

Test Cases: Remove from Cart

# tests/test_remove_from_cart.py
class TestRemoveFromCart:

    def test_remove_single_item(self, driver, cart_with_one_item):
        """
        Given: Cart has 1 item
        When: User clicks Remove
        Then: Cart is empty
        """
        cart = cart_with_one_item
        cart.remove_item(0)

        assert cart.is_empty()
        assert cart.get_item_count() == 0

    def test_remove_one_of_multiple_items(self, driver, cart_with_three_items):
        """
        Given: Cart has 3 items
        When: User removes item at index 1
        Then: Cart has 2 items
        And: Removed item is no longer present
        """
        cart = cart_with_three_items
        item_to_remove = cart.get_item_by_index(1).title

        cart.remove_item(1)

        assert cart.get_item_count() == 2
        remaining_titles = [cart.get_item_by_index(i).title
                          for i in range(cart.get_item_count())]
        assert item_to_remove not in remaining_titles

    def test_remove_updates_total(self, driver, cart_with_items):
        """
        Given: Cart has items with total $X
        When: User removes an item worth $Y
        Then: New total is $X - $Y
        """
        cart = cart_with_items
        original_total = cart.get_total()
        item_price = cart.get_item_by_index(0).price

        cart.remove_item(0)

        new_total = cart.get_total()
        assert abs(new_total - (original_total - item_price)) < 0.01

    def test_clear_cart(self, driver, cart_with_three_items):
        """
        Given: Cart has multiple items
        When: User removes all items
        Then: Empty cart message is shown
        """
        cart = cart_with_three_items

        while cart.get_item_count() > 0:
            cart.remove_item(0)

        assert cart.is_empty()
        assert "empty" in cart.get_text(cart.EMPTY_CART_MSG).lower()

Test Cases: Update Quantity

# tests/test_update_quantity.py
class TestUpdateQuantity:

    def test_increase_quantity(self, driver, cart_with_one_item):
        """
        Given: Cart has 1 item with quantity 1
        When: User changes quantity to 3
        Then: Quantity is updated to 3
        """
        cart = cart_with_one_item
        cart.update_quantity(0, 3)

        assert cart.get_item_by_index(0).quantity == 3

    def test_decrease_quantity(self, driver, cart_with_one_item):
        """
        Given: Cart has 1 item with quantity 3
        When: User changes quantity to 1
        Then: Quantity is updated to 1
        """
        cart = cart_with_one_item
        cart.update_quantity(0, 3)  # Setup: set to 3
        cart.update_quantity(0, 1)  # Test: decrease to 1

        assert cart.get_item_by_index(0).quantity == 1

    def test_quantity_updates_subtotal(self, driver, cart_with_one_item):
        """
        Given: Item costs $10
        When: User changes quantity to 3
        Then: Item subtotal shows $30
        """
        cart = cart_with_one_item
        item = cart.get_item_by_index(0)
        unit_price = item.price

        cart.update_quantity(0, 3)

        # Verify subtotal (item price * quantity)
        expected_subtotal = unit_price * 3
        actual_subtotal = item.subtotal  # Need to add this property
        assert abs(actual_subtotal - expected_subtotal) < 0.01

    def test_quantity_zero_removes_item(self, driver, cart_with_one_item):
        """
        Given: Cart has 1 item
        When: User changes quantity to 0
        Then: Item is removed from cart
        """
        cart = cart_with_one_item
        cart.update_quantity(0, 0)

        assert cart.is_empty() or cart.get_item_count() == 0

    def test_quantity_exceeds_stock(self, driver, cart_with_one_item):
        """
        Given: Item has 5 in stock
        When: User tries to set quantity to 10
        Then: Error message is shown
        And: Quantity is capped at 5
        """
        cart = cart_with_one_item

        cart.update_quantity(0, 10)  # Exceeds stock

        # Check for error or warning
        assert cart.is_visible(cart.QUANTITY_ERROR) or \
               cart.get_item_by_index(0).quantity <= 5

Test Cases: Cart Persistence

# tests/test_cart_persistence.py
class TestCartPersistence:

    def test_cart_persists_on_page_refresh(self, driver, cart_with_one_item):
        """
        Given: Cart has 1 item
        When: User refreshes the page
        Then: Cart still has 1 item
        """
        cart = cart_with_one_item
        item_title = cart.get_item_by_index(0).title

        driver.refresh()

        # Re-instantiate page object after refresh
        from pages.cart_page import CartPage
        cart = CartPage(driver)

        assert cart.get_item_count() == 1
        assert cart.get_item_by_index(0).title == item_title

    def test_cart_persists_in_new_tab(self, driver, cart_with_one_item):
        """
        Given: Cart has items in Tab 1
        When: User opens cart in new tab
        Then: New tab shows same cart contents
        """
        cart = cart_with_one_item
        original_count = cart.get_item_count()

        # Open new tab
        driver.execute_script("window.open('');")
        driver.switch_to.window(driver.window_handles[1])

        # Navigate to cart in new tab
        from pages.cart_page import CartPage
        cart_new_tab = CartPage(driver).open()

        assert cart_new_tab.get_item_count() == original_count

        # Cleanup: close new tab
        driver.close()
        driver.switch_to.window(driver.window_handles[0])

    def test_cart_persists_after_login(self, driver):
        """
        Given: Guest user has items in cart
        When: User logs in
        Then: Cart items are preserved
        """
        # Add as guest
        products = ProductsPage(driver).open()
        products.add_product_to_cart(0)

        guest_cart_count = Header(driver).get_cart_count()

        # Login
        login_page = LoginPage(driver).open()
        login_page.login("test@example.com", "password123")

        # Check cart
        assert Header(driver).get_cart_count() == guest_cart_count

Test Cases: Cart Calculations

# tests/test_cart_calculations.py
class TestCartCalculations:

    def test_cart_total_matches_item_sum(self, driver, cart_with_multiple_items):
        """
        Given: Cart has multiple items
        Then: Total equals sum of all item subtotals
        """
        cart = cart_with_multiple_items

        expected_total = 0
        for i in range(cart.get_item_count()):
            item = cart.get_item_by_index(i)
            expected_total += item.price * item.quantity

        actual_total = cart.get_total()
        assert abs(actual_total - expected_total) < 0.01

    def test_promo_code_applies_discount(self, driver, cart_with_one_item):
        """
        Given: Cart total is $100
        When: User applies 10% off promo code
        Then: Total shows $90
        """
        cart = cart_with_one_item
        # Ensure cart has predictable value
        original_total = cart.get_total()

        cart.apply_promo_code("SAVE10")

        # Check discount applied
        new_total = cart.get_total()
        expected = original_total * 0.9
        assert abs(new_total - expected) < 0.01

    def test_invalid_promo_code_shows_error(self, driver, cart_with_one_item):
        """
        Given: User enters invalid promo code
        Then: Error message is displayed
        And: Total is unchanged
        """
        cart = cart_with_one_item
        original_total = cart.get_total()

        cart.apply_promo_code("INVALID123")

        assert cart.is_visible(cart.PROMO_ERROR)
        assert cart.get_total() == original_total

Fixtures for Cart Tests

# tests/conftest.py
import pytest
from pages.products_page import ProductsPage
from pages.cart_page import CartPage
from pages.components.header import Header

@pytest.fixture
def cart_with_one_item(driver):
    """Provide cart with single item"""
    products = ProductsPage(driver).open()
    products.add_product_to_cart(0)
    return Header(driver).go_to_cart()

@pytest.fixture
def cart_with_three_items(driver):
    """Provide cart with three different items"""
    products = ProductsPage(driver).open()
    products.add_product_to_cart(0)
    products.add_product_to_cart(1)
    products.add_product_to_cart(2)
    return Header(driver).go_to_cart()

@pytest.fixture
def cart_with_multiple_items(driver):
    """Alias for cart_with_three_items"""
    return cart_with_three_items(driver)

Edge Cases to Consider

ScenarioTest Approach
Add to cart while not logged inVerify guest cart works
Cart item goes out of stockCheck warning/removal
Price changes after addingVerify updated price shows
Network error during addTest error handling
Concurrent cart updatesTwo tabs adding items

Key Takeaways

  • Prioritize revenue-critical paths - Add, remove, checkout
  • Test calculations precisely - Use small tolerance (0.01) for floating point
  • Verify persistence - Refresh, new tab, login
  • Use fixtures for setup - DRY test code
  • Cover edge cases - Out of stock, invalid input, errors

Next Lesson

The cart leads to Checkout & Payment Testingโ€”the most critical (and complex) part of e-commerce testing.