Why QA Engineers Need Git

Every professional test automation project uses version control. Git is the industry standard. As a QA automation engineer, you will:

  • Store test code in repositories alongside application code
  • Create branches for new test suites and features
  • Submit pull requests for code review
  • Resolve merge conflicts when multiple people edit tests
  • Use Git history to understand when and why tests changed
  • Integrate with CI/CD pipelines that trigger on Git events

Essential Git Commands

Setting Up

# Configure your identity
git config --global user.name "Your Name"
git config --global user.email "your.email@company.com"

# Clone a repository
git clone https://github.com/company/test-automation.git
cd test-automation

# Check current status
git status

Daily Workflow Commands

# Get latest changes from remote
git pull origin main

# Create a new branch for your work
git checkout -b feature/add-login-tests

# Check which files you changed
git status
git diff

# Stage specific files
git add tests/login.spec.ts
git add tests/fixtures/users.json

# Commit with a descriptive message
git commit -m "Add login page test suite with positive and negative scenarios"

# Push your branch to remote
git push origin feature/add-login-tests

Viewing History

# View commit history
git log --oneline -20

# See what changed in a specific commit
git show abc1234

# See who last modified each line of a file
git blame tests/login.spec.ts

# Find when a test was added or modified
git log --follow tests/checkout.spec.ts

Branching Strategy for Test Code

Branch Naming Conventions

Use clear, descriptive branch names:

feature/add-checkout-tests      # New test suite
feature/POM-login-page          # New page object
fix/flaky-search-test           # Fix a flaky test
refactor/base-test-class        # Refactor existing code
chore/update-playwright-version # Dependency update

The Feature Branch Workflow

main ─────────────────────────────────────────
       \                              /
        feature/add-login-tests ─────
  1. Create a branch from main
  2. Make your changes and commit
  3. Push to remote and open a pull request
  4. Get code review from teammates
  5. CI runs your tests automatically
  6. Merge after approval

Keeping Your Branch Updated

# While working on your branch, main may have new commits
git checkout main
git pull origin main
git checkout feature/add-login-tests
git rebase main

# Or merge main into your branch
git merge main

The Pull Request Process

Creating a Good PR for Test Code

A good pull request includes:

Title: Clear description of what tests are added/changed

Add login page E2E tests with edge cases

Description:

## What
- Added 12 test cases for the login page
- Covers positive login, invalid credentials, account lockout, SSO

## Test Coverage
- Happy path: valid email/password login
- Negative: wrong password (3 attempts → lockout)
- Edge cases: SQL injection in email field, XSS in password
- SSO: Google and GitHub OAuth flows

## Page Objects Added
- LoginPage: login(), forgotPassword(), socialLogin()
- DashboardPage: verifyWelcome(), logout()

## How to Run
npm run test:login

Code Review Checklist for Test Code

When reviewing test PRs, check for:

  • Tests have clear, descriptive names
  • No hardcoded test data (use fixtures or factories)
  • Proper use of page objects (no raw selectors in tests)
  • Assertions are specific and meaningful
  • Tests are independent (no order dependency)
  • Cleanup is handled (test data, browser state)
  • No unnecessary waits or sleeps

Handling Merge Conflicts

Merge conflicts happen when two people edit the same file. In test automation, this commonly occurs in:

  • Shared page objects
  • Test configuration files
  • Test data files

Resolving a Conflict

# When you see a conflict after merge or rebase
# Git marks the conflicting sections:

<<<<<<< HEAD (your changes)
async login(email, password) {
  await this.page.fill('#email-v2', email);
}
=======
async login(email, password) {
  await this.page.fill('[data-testid="email"]', email);
}
>>>>>>> main (incoming changes)

# Resolve by choosing the correct version or combining both
async login(email, password) {
  await this.page.fill('[data-testid="email"]', email);
}

# Then stage and commit
git add tests/pages/login.page.ts
git commit -m "Resolve merge conflict: use data-testid selector for email"

.gitignore for Test Projects

A proper .gitignore prevents unnecessary files from cluttering the repository:

# Test results and reports
test-results/
playwright-report/
allure-results/
allure-report/
coverage/

# Screenshots and videos from test runs
screenshots/
videos/
traces/

# Dependencies
node_modules/
.venv/

# IDE files
.vscode/
.idea/
*.swp

# Environment files with secrets
.env
.env.local

# OS files
.DS_Store
Thumbs.db

# Build output
dist/
build/

Git Hooks for Test Quality

Git hooks run scripts automatically at specific Git events. Use them to enforce test quality:

Pre-Commit Hook

Run linting before every commit:

#!/bin/sh
# .git/hooks/pre-commit
npx eslint tests/ --ext .ts,.js
if [ $? -ne 0 ]; then
  echo "Linting failed. Fix issues before committing."
  exit 1
fi

Pre-Push Hook

Run tests before pushing:

#!/bin/sh
# .git/hooks/pre-push
npx playwright test --grep @smoke
if [ $? -ne 0 ]; then
  echo "Smoke tests failed. Fix before pushing."
  exit 1
fi

Advanced Git for QA

Stashing Work in Progress

# Save uncommitted changes temporarily
git stash save "WIP: checkout tests"

# Switch to another branch to fix something urgent
git checkout fix/flaky-login-test

# Come back and restore your work
git checkout feature/checkout-tests
git stash pop

Cherry-Picking a Fix

# Apply a specific commit from another branch
git cherry-pick abc1234

Bisecting to Find When a Test Broke

# Find which commit introduced a bug
git bisect start
git bisect bad           # Current commit is broken
git bisect good abc1234  # This old commit was working

# Git checks out a middle commit — run your test
npx playwright test tests/login.spec.ts

# Tell Git the result
git bisect good  # or git bisect bad

# Repeat until Git finds the culprit commit
git bisect reset  # When done

Collaboration Best Practices

Commit Message Guidelines

# Good commit messages
git commit -m "Add checkout flow E2E tests for guest and registered users"
git commit -m "Fix flaky product search test: increase wait timeout for API response"
git commit -m "Refactor LoginPage: extract form fill methods to BaseFormPage"

# Bad commit messages
git commit -m "fix tests"
git commit -m "update"
git commit -m "WIP"

Atomic Commits

Each commit should be a logical unit:

  • One commit per feature or fix
  • Tests should pass after each commit
  • Do not mix unrelated changes

Exercise: Git Workflow Practice

Practice the following workflow:

  1. Clone a test repository (or create a new one)
  2. Create a branch feature/add-search-tests
  3. Add a test file tests/search.spec.ts with two test cases
  4. Commit with a descriptive message
  5. Create a second branch feature/add-filter-tests from main
  6. Modify the same configuration file on both branches
  7. Merge both branches and resolve any conflicts
  8. View the commit history with git log --graph --oneline

Key Takeaways

  • Use feature branches for all test code changes
  • Write descriptive commit messages explaining what and why
  • Always pull latest changes before starting new work
  • Handle merge conflicts by understanding both changes
  • Use .gitignore to keep test results and reports out of the repo
  • Git hooks automate quality checks before commit and push