Module 2: Understanding Git's Three Areas: Working, Staging, and Repository

Master the fundamental workflow of Git by understanding the three core areas. Learn how test files move through Working Directory, Staging Area, and Repository. Practice selective staging to commit only relevant test changes, and understand how to inspect and manipulate files at each stage.

Inspecting and Navigating Between Areas

Why This Matters

As a test automation engineer, you’re constantly creating, modifying, and organizing test files—from new test cases and page objects to updated configuration files and test data. But not every change you make should end up in the same commit. Imagine you’ve fixed a critical bug in one test suite while also experimenting with a new framework feature in another. Without understanding Git’s three-area workflow, you might accidentally commit half-finished experiments alongside production-ready fixes, creating confusion for your team and cluttering your project history.

This lesson solves real problems you face daily:

  • Selective commits: You need to commit bug fixes separately from new feature tests, even when both are modified simultaneously
  • Code review efficiency: Reviewers expect focused, logical commits—not a jumble of unrelated test changes
  • Safe experimentation: You want to try new testing approaches without affecting stable test code
  • Collaboration clarity: Your team needs to understand exactly what changed and why, commit by commit

You’ll use these skills every time you:

  • Work on multiple test features or bug fixes in parallel
  • Need to commit only part of your current changes
  • Want to review what you’re about to commit before finalizing
  • Troubleshoot why certain changes aren’t being tracked or committed
  • Collaborate with team members on shared test automation repositories

Common pain points this lesson addresses:

  • “I ran git commit but my changes didn’t save!”
  • “How do I commit only these two test files and not the others?”
  • “What’s the difference between modified and staged files?”
  • “I can’t see what I’m about to commit before I commit it”
  • “Git says I have changes, but I don’t know where they are”

Learning Objectives Overview

By the end of this lesson, you’ll have a complete mental model of how Git manages your test automation files through three distinct areas. Here’s what you’ll accomplish:

Understanding the Three-Area Architecture
You’ll learn how Git organizes your work into the Working Directory (where you edit), Staging Area (where you prepare), and Repository (where you save). We’ll use test automation examples to make each area concrete and understandable.

Mastering File Inspection
You’ll practice using git status to see which area your files are in, and learn to interpret Git’s messages about untracked, modified, and staged files—essential for knowing the state of your test suite at any moment.

Navigating Files Between Areas
You’ll move test files forward (from Working Directory to Staging Area with git add) and backward (from Staging Area to Working Directory with git reset), giving you complete control over what gets committed and when.

Practicing Selective Staging
Through hands-on exercises with realistic test scenarios, you’ll stage only specific files or even specific lines within files, enabling you to create focused, logical commits that tell a clear story.

Comparing Changes with git diff
You’ll learn multiple git diff variations to compare your Working Directory against the Staging Area, the Staging Area against the Repository, and even specific files between areas—giving you x-ray vision into your changes before committing.

Understanding the Complete File Journey
You’ll trace test files from creation (untracked) through modification, staging, and finally to committed—building the foundational workflow that every advanced Git operation builds upon.

Each objective includes practical examples using test automation files, so you’ll be working with scenarios directly relevant to your daily work as a test engineer.


Core Content

Core Content: Inspecting and Navigating Between Areas

Core Concepts Explained

Understanding Test Automation Navigation

In test automation, inspecting and navigating between areas refers to the ability to identify, locate, and interact with different elements and sections of a web application. This is a fundamental skill that bridges the gap between writing simple linear tests and creating robust, maintainable automation suites.

The Three Pillars of Navigation

  1. Element Inspection - Understanding the structure of web elements and their properties
  2. Locator Strategies - Choosing the right method to find elements reliably
  3. Navigation Patterns - Moving between pages, frames, and dynamic content

Browser Developer Tools for Test Automation

Before writing any automation code, you need to inspect the application structure:

Key Developer Tools Features:

  • Elements Tab: View the DOM structure and element properties
  • Selector Tool: Click elements to see their HTML structure
  • Console: Test selectors and JavaScript interactions
  • Network Tab: Monitor page loads and AJAX requests
graph TD
    A[Open Browser DevTools] --> B[Inspect Element]
    B --> C{Choose Locator Strategy}
    C --> D[ID - Most Reliable]
    C --> E[CSS Selector - Flexible]
    C --> F[XPath - Powerful]
    C --> G[Text Content - User-Facing]
    D --> H[Write Automation Code]
    E --> H
    F --> H
    G --> H

Locator Strategy Hierarchy

Understanding which locator to use is critical for test stability:

Priority Locator Type Use When Stability
1 ID Element has unique ID Highest
2 Name Form elements with name attributes High
3 CSS Selector Complex combinations needed Medium-High
4 XPath Navigating DOM relationships Medium
5 Link Text Clicking links Medium-Low
6 Class Name Last resort, often non-unique Lowest

Practical Code Examples

Example 1: Inspecting and Navigating Form Elements

Let’s work with practiceautomatedtesting.com to demonstrate element inspection and navigation:

// Selenium WebDriver (JavaScript/Node.js)
const { Builder, By, until } = require('selenium-webdriver');

async function navigateAndInspectForm() {
    // Initialize driver
    let driver = await new Builder().forBrowser('chrome').build();
    
    try {
        // Navigate to the practice site
        await driver.get('http://practiceautomatedtesting.com');
        
        // Strategy 1: Using ID (Most Reliable)
        const emailField = await driver.findElement(By.id('email'));
        await emailField.sendKeys('user@example.com');
        
        // Strategy 2: Using Name attribute
        const passwordField = await driver.findElement(By.name('password'));
        await passwordField.sendKeys('SecurePass123');
        
        // Strategy 3: Using CSS Selector
        const submitButton = await driver.findElement(
            By.css('button[type="submit"]')
        );
        
        // Strategy 4: Using XPath for complex navigation
        const termsCheckbox = await driver.findElement(
            By.xpath('//label[contains(text(), "Terms")]/preceding-sibling::input')
        );
        await termsCheckbox.click();
        
        // Wait for element to be visible before interacting
        await driver.wait(until.elementIsVisible(submitButton), 5000);
        await submitButton.click();
        
    } finally {
        await driver.quit();
    }
}

Example 2: Navigating Between Multiple Page Areas

# Selenium WebDriver (Python)
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def navigate_multiple_areas():
    driver = webdriver.Chrome()
    wait = WebDriverWait(driver, 10)
    
    try:
        driver.get("http://practiceautomatedtesting.com")
        
        # Navigate to header navigation
        home_link = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "nav a[href='/']"))
        )
        
        # Navigate to main content area
        main_heading = driver.find_element(By.CSS_SELECTOR, "main h1")
        print(f"Current page: {main_heading.text}")
        
        # Navigate to footer area
        footer_links = driver.find_elements(
            By.CSS_SELECTOR, 
            "footer a"
        )
        print(f"Found {len(footer_links)} footer links")
        
        # Navigate to sidebar (if exists)
        try:
            sidebar = driver.find_element(By.CSS_SELECTOR, "aside")
            sidebar_items = sidebar.find_elements(By.TAG_NAME, "li")
            
            # Iterate through sidebar navigation
            for idx, item in enumerate(sidebar_items, 1):
                print(f"Sidebar item {idx}: {item.text}")
        except:
            print("No sidebar found on this page")
            
    finally:
        driver.quit()

Example 3: Handling Dynamic Content and Frames

// Playwright (JavaScript) - Modern approach
const { chromium } = require('playwright');

async function inspectDynamicAreas() {
    const browser = await chromium.launch({ headless: false });
    const page = await browser.newPage();
    
    try {
        await page.goto('http://practiceautomatedtesting.com');
        
        // Wait for dynamic content to load
        await page.waitForSelector('#dynamic-content', { 
            state: 'visible',
            timeout: 5000 
        });
        
        // Navigate to iframe content
        const frameElement = await page.frameLocator('iframe[name="content"]');
        const frameButton = frameElement.locator('button.submit');
        await frameButton.click();
        
        // Switch back to main content
        const mainContent = page.locator('main');
        
        // Navigate through tabs/sections
        const tabs = await page.locator('[role="tab"]').all();
        for (const tab of tabs) {
            await tab.click();
            // Wait for tab content to load
            await page.waitForTimeout(500);
            
            const activePanel = page.locator('[role="tabpanel"]:visible');
            const content = await activePanel.textContent();
            console.log(`Tab content: ${content}`);
        }
        
    } finally {
        await browser.close();
    }
}

Example 4: Relative Locators and Advanced Navigation

// Selenium 4 - Java with Relative Locators
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import static org.openqa.selenium.support.locators.RelativeLocator.with;

public class RelativeNavigation {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        
        try {
            driver.get("http://practiceautomatedtesting.com");
            
            // Find an anchor element
            WebElement loginButton = driver.findElement(By.id("login"));
            
            // Find element ABOVE login button
            WebElement headerText = driver.findElement(
                with(By.tagName("h2")).above(loginButton)
            );
            
            // Find element BELOW login button
            WebElement forgotPassword = driver.findElement(
                with(By.tagName("a")).below(loginButton)
            );
            
            // Find element to the RIGHT
            WebElement signupLink = driver.findElement(
                with(By.tagName("a")).toRightOf(loginButton)
            );
            
            // Find element NEAR (within 50 pixels)
            WebElement nearbyElement = driver.findElement(
                with(By.tagName("span")).near(loginButton)
            );
            
            System.out.println("Header: " + headerText.getText());
            System.out.println("Forgot link: " + forgotPassword.getText());
            
        } finally {
            driver.quit();
        }
    }
}

Example 5: Building a Navigation Helper Class

# Page Object Model - Navigation Helper
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class NavigationHelper:
    """Helper class for inspecting and navigating page areas"""
    
    def __init__(self, driver):
        self.driver = driver
        self.wait = WebDriverWait(driver, 10)
    
    def find_element_safely(self, locator_type, locator_value):
        """Find element with explicit wait"""
        locator = (locator_type, locator_value)
        return self.wait.until(EC.presence_of_element_located(locator))
    
    def navigate_to_area(self, area_selector):
        """Navigate to specific page area"""
        element = self.find_element_safely(By.CSS_SELECTOR, area_selector)
        self.driver.execute_script("arguments[0].scrollIntoView(true);", element)
        return element
    
    def get_all_links_in_area(self, area_selector):
        """Get all links within a specific area"""
        area = self.find_element_safely(By.CSS_SELECTOR, area_selector)
        links = area.find_elements(By.TAG_NAME, "a")
        return [link.get_attribute("href") for link in links]
    
    def is_in_viewport(self, element):
        """Check if element is visible in viewport"""
        return self.driver.execute_script("""
            var elem = arguments[0];
            var rect = elem.getBoundingClientRect();
            return (
                rect.top >= 0 &&
                rect.left >= 0 &&
                rect.bottom <= window.innerHeight &&
                rect.right <= window.innerWidth
            );
        """, element)

# Usage example
def test_navigation():
    from selenium import webdriver
    
    driver = webdriver.Chrome()
    nav_helper = NavigationHelper(driver)
    
    try:
        driver.get("http://practiceautomatedtesting.com")
        
        # Navigate to header
        header = nav_helper.navigate_to_area("header")
        print(f"Header visible: {nav_helper.is_in_viewport(header)}")
        
        # Get all footer links
        footer_links = nav_helper.get_all_links_in_area("footer")
        print(f"Footer links: {footer_links}")
        
    finally:
        driver.quit()

Common Mistakes Section

❌ Mistake 1: Using Unreliable Locators

// BAD: Using index-based XPath
const element = await driver.findElement(By.xpath('//div[3]/span[2]/a[1]'));

// GOOD: Using semantic locators
const element = await driver.findElement(By.css('a[data-testid="submit-form"]'));

Why it fails: Index-based locators break when page structure changes.

❌ Mistake 2: Not Waiting for Elements

# BAD: Immediate interaction
driver.get("http://practiceautomatedtesting.com")
button = driver.find_element(By.ID, "submit")
button.click()  # May fail if page not fully loaded

# GOOD: Explicit wait
wait = WebDriverWait(driver, 10)
button = wait.until(EC.element_to_be_clickable((By.ID, "submit")))
button.click()

Why it fails: Elements may not be ready for interaction immediately after page load.

❌ Mistake 3: Ignoring Frame Context

// BAD: Trying to access iframe content directly
const iframeButton = await driver.findElement(By.id('button-in-frame'));

// GOOD: Switch to frame first
await driver.switchTo().frame('frame-name');
const iframeButton = await driver.findElement(By.id('button-in-frame'));
await iframeButton.click();
await driver.switchTo().defaultContent(); // Switch back

Why it fails: Elements inside iframes require context switching.

❌ Mistake 4: Not Handling Stale Elements

# BAD: Reusing element after page change
elements = driver.find_elements(By.CLASS_NAME, "item")
first_element = elements[0]
first_element.click()  # Page changes
first_element.click()  # StaleElementReferenceException

# GOOD: Re-query after page changes
elements = driver.find_elements(By.CLASS_NAME, "item")
elements[0].click()
# After page change, query again
elements = driver.find_elements(By.CLASS_NAME, "item")
elements[0].click()

Why it fails: DOM references become stale after page updates.

Debugging Navigation Issues

Diagnostic Commands:

# Check element properties in browser console
document.querySelector('#element-id')

# Verify selector returns elements
document.querySelectorAll('.my-class').length

# Check if element is in iframe
document.querySelector('iframe').contentDocument.querySelector('#element')

Common Solutions:

  1. Element not found → Add explicit waits
  2. Element not clickable → Scroll into view first
  3. Stale element → Re-query the element
  4. Wrong element selected → Use more specific locators
  5. Timing issues → Increase wait timeout or use better wait conditions
graph TD
    A[Element Not Found] --> B{Check DevTools}
    B -->|Selector Wrong| C[Refine Locator]
    B -->|Element Exists| D{Is it in iframe?}
    D -->|Yes| E[Switch to Frame]
    D -->|No| F{Is it visible?}
    F -->|No| G[Wait for Visibility]
    F -->|Yes| H{Timing Issue?}
    H -->|Yes| I[Add Explicit Wait]
    H -->|No| J[Check Element State]

Hands-On Practice

Hands-On Exercise

Task: Build a Multi-Area Navigation Test Suite

Create an automated test that validates navigation and element inspection across different areas of a sample e-commerce website (login page, product catalog, shopping cart, and checkout).

Scenario

You’re testing a shopping workflow that requires navigating between multiple page areas and verifying elements in each section.

Requirements

  1. Inspect and verify elements in the header navigation area
  2. Navigate to the product catalog and locate specific product cards
  3. Inspect the shopping cart area after adding items
  4. Verify the checkout form elements and their states
  5. Use appropriate locator strategies for each area

Step-by-Step Instructions

Step 1: Set up your test structure

# starter_code.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class NavigationTest:
    def __init__(self):
        self.driver = webdriver.Chrome()
        self.wait = WebDriverWait(self.driver, 10)
        self.base_url = "https://demo-store.example.com"  # Use your test site
    
    def setup(self):
        self.driver.get(self.base_url)
        self.driver.maximize_window()
    
    def teardown(self):
        self.driver.quit()
    
    # TODO: Implement the following methods
    def test_header_navigation(self):
        pass
    
    def test_product_catalog_area(self):
        pass
    
    def test_shopping_cart_area(self):
        pass
    
    def test_checkout_form_area(self):
        pass

Step 2: Inspect and test the header navigation area

  • Locate the main navigation menu
  • Verify all navigation links are present and visible
  • Test navigation between different sections

Step 3: Navigate to and inspect the product catalog

  • Switch to the products area
  • Use appropriate locators to find product cards
  • Verify product information is displayed correctly
  • Add a product to the cart

Step 4: Inspect the shopping cart area

  • Navigate to the cart section
  • Verify cart items are displayed
  • Check quantity selectors and remove buttons
  • Validate cart total calculations

Step 5: Navigate to checkout and inspect form elements

  • Move to the checkout area
  • Locate form fields (name, email, address, etc.)
  • Verify field states (enabled, required attributes)
  • Check validation messages

Expected Outcome

Your test suite should:

  • ✅ Successfully navigate between all four areas
  • ✅ Correctly identify elements within each area using appropriate locators
  • ✅ Verify element states and visibility in each section
  • ✅ Handle dynamic content and wait for elements to load
  • ✅ Provide clear assertion messages for each verification

Solution Approach

# solution.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class NavigationTest:
    def __init__(self):
        self.driver = webdriver.Chrome()
        self.wait = WebDriverWait(self.driver, 10)
        self.base_url = "https://demo-store.example.com"
    
    def setup(self):
        self.driver.get(self.base_url)
        self.driver.maximize_window()
    
    def test_header_navigation(self):
        """Inspect header area and verify navigation elements"""
        # Locate header navigation area
        header = self.wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "header.main-header"))
        )
        
        # Inspect navigation links within header
        nav_links = header.find_elements(By.CSS_SELECTOR, "nav.main-nav a")
        assert len(nav_links) >= 4, "Expected at least 4 navigation links"
        
        # Verify all links are visible
        for link in nav_links:
            assert link.is_displayed(), f"Link {link.text} is not visible"
        
        print("✓ Header navigation area verified")
    
    def test_product_catalog_area(self):
        """Navigate to catalog and inspect product elements"""
        # Navigate to products section
        products_link = self.wait.until(
            EC.element_to_be_clickable((By.LINK_TEXT, "Products"))
        )
        products_link.click()
        
        # Wait for product catalog area to load
        catalog_area = self.wait.until(
            EC.presence_of_element_located((By.CLASS_NAME, "product-catalog"))
        )
        
        # Inspect product cards within catalog area
        product_cards = catalog_area.find_elements(By.CSS_SELECTOR, ".product-card")
        assert len(product_cards) > 0, "No products found in catalog"
        
        # Inspect first product's elements
        first_product = product_cards[0]
        product_name = first_product.find_element(By.CLASS_NAME, "product-name")
        product_price = first_product.find_element(By.CLASS_NAME, "product-price")
        add_to_cart_btn = first_product.find_element(By.CSS_SELECTOR, "button.add-to-cart")
        
        assert product_name.is_displayed()
        assert product_price.is_displayed()
        
        # Add product to cart
        add_to_cart_btn.click()
        print("✓ Product catalog area inspected and item added to cart")
    
    def test_shopping_cart_area(self):
        """Navigate to cart and inspect cart elements"""
        # Navigate to cart area
        cart_icon = self.wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, ".cart-icon"))
        )
        cart_icon.click()
        
        # Wait for cart area to be visible
        cart_area = self.wait.until(
            EC.visibility_of_element_located((By.CLASS_NAME, "shopping-cart"))
        )
        
        # Inspect cart items
        cart_items = cart_area.find_elements(By.CLASS_NAME, "cart-item")
        assert len(cart_items) > 0, "Cart should contain items"
        
        # Inspect first cart item elements
        first_item = cart_items[0]
        item_name = first_item.find_element(By.CLASS_NAME, "item-name")
        quantity_input = first_item.find_element(By.CSS_SELECTOR, "input[type='number']")
        remove_btn = first_item.find_element(By.CLASS_NAME, "remove-item")
        
        assert item_name.is_displayed()
        assert quantity_input.is_enabled()
        assert remove_btn.is_displayed()
        
        # Verify cart total
        cart_total = cart_area.find_element(By.CLASS_NAME, "cart-total")
        assert cart_total.is_displayed()
        
        print("✓ Shopping cart area verified")
    
    def test_checkout_form_area(self):
        """Navigate to checkout and inspect form elements"""
        # Navigate to checkout
        checkout_btn = self.wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "button.checkout"))
        )
        checkout_btn.click()
        
        # Wait for checkout form area
        checkout_form = self.wait.until(
            EC.presence_of_element_located((By.ID, "checkout-form"))
        )
        
        # Inspect form fields
        name_field = checkout_form.find_element(By.ID, "customer-name")
        email_field = checkout_form.find_element(By.ID, "customer-email")
        address_field = checkout_form.find_element(By.ID, "customer-address")
        
        # Verify field states
        assert name_field.is_enabled(), "Name field should be enabled"
        assert email_field.is_enabled(), "Email field should be enabled"
        assert address_field.is_enabled(), "Address field should be enabled"
        
        # Check required attributes
        assert name_field.get_attribute("required") is not None
        assert email_field.get_attribute("required") is not None
        
        # Locate submit button
        submit_btn = checkout_form.find_element(By.CSS_SELECTOR, "button[type='submit']")
        assert submit_btn.is_displayed()
        
        print("✓ Checkout form area verified")
    
    def run_all_tests(self):
        try:
            self.setup()
            self.test_header_navigation()
            self.test_product_catalog_area()
            self.test_shopping_cart_area()
            self.test_checkout_form_area()
            print("\n✅ All navigation and inspection tests passed!")
        finally:
            self.teardown()

# Run the tests
if __name__ == "__main__":
    test = NavigationTest()
    test.run_all_tests()

Key Takeaways

  • Area-specific locators are essential: Use parent-child relationships to locate elements within specific page areas, reducing ambiguity and improving test reliability (e.g., header.find_element() instead of searching the entire DOM)

  • Navigation requires proper waits: Always wait for target areas to load completely before inspecting elements using WebDriverWait with appropriate expected conditions like presence_of_element_located or visibility_of_element_located

  • Hierarchical element inspection improves maintainability: Structure your locators by first identifying the container/area, then locating elements within it. This creates more resilient tests that adapt better to page changes

  • Different areas need different verification strategies: Header elements might need visibility checks, form fields need state verification (enabled/disabled), and dynamic areas like shopping carts need content validation

  • Context switching between areas is a common pattern: Real-world testing frequently requires navigating between multiple page sections in a single test flow, so understanding how to cleanly transition and verify each area is crucial


Next Steps

What to Practice

  • Complex page layouts: Practice with applications that have sidebars, modals, nested navigation, and multi-panel interfaces
  • Dynamic content areas: Work with sections that update without page reloads (AJAX/SPA applications)
  • Mobile-responsive areas: Test how element inspection changes between desktop and mobile viewports
  • Shadow DOM navigation: Learn to inspect elements within web components and shadow DOM boundaries
  • Page Object Model (POM): Structure your area-specific locators and navigation methods into reusable page objects
  • Explicit waits and custom expected conditions: Create custom wait conditions for complex area transitions
  • Cross-browser element inspection: Understand how different browsers handle area identification and element locators
  • Accessibility tree navigation: Use ARIA landmarks and roles to identify page areas more reliably
  • iFrame and frame switching: Navigate between embedded frames and windows in your application