Module 7: Remote Repositories: Collaborating on Test Automation

Connect your local test repository to remote platforms like GitHub and GitLab. Learn to push test changes, pull updates from teammates, manage remote branches, and collaborate effectively on shared test automation projects. Set up CI/CD integration basics for automated test execution.

Team Workflows: Pull Requests and Code Review for Test Automation

Why This Matters

You’ve written excellent test automation code on your local machine, but now you need to share it with your team. Simply pushing directly to the main branch creates chaos—untested code breaks the pipeline, teammates overwrite each other’s work, and there’s no accountability for quality. This is where pull requests and code review workflows become essential.

Real-world scenarios where this matters:

  • Quality Assurance: Before your test code reaches production, multiple eyes review it for logic errors, missed edge cases, and maintainability issues. A recent study showed that code review catches 60% of defects before they enter the main codebase.

  • Knowledge Sharing: When a teammate reviews your Selenium page object or API test suite, they learn your testing approach. When you review theirs, you discover new patterns and techniques. This cross-pollination makes the entire team stronger.

  • Risk Mitigation: Automated tests are your safety net. Broken or flaky tests are worse than no tests at all. Pull requests with automated test runs catch issues before they break your team’s workflow.

  • Compliance and Audit Trails: Many regulated industries require documented evidence that test changes were reviewed and approved. Pull requests provide this audit trail automatically.

Common pain points this lesson addresses:

  • Tests that work locally but fail in CI environments
  • Merge conflicts in shared test utilities and fixtures
  • Inconsistent test patterns across team members
  • Flaky tests that slip into the main branch
  • Lack of visibility into what test coverage exists
  • Difficulty maintaining test quality standards across a growing team

What You’ll Accomplish

By the end of this lesson, you’ll have a complete pull request workflow for your test automation projects. You’ll move beyond solo Git usage to true team collaboration.

Here’s how we’ll cover each learning objective:

Creating Feature Branches: You’ll learn the feature branch workflow—creating isolated branches for each test suite or feature you’re developing. We’ll cover naming conventions (test/login-validation, fix/flaky-checkout-test) and when to branch from main versus develop.

Submitting Pull Requests: You’ll practice creating PRs on GitHub and GitLab, writing clear descriptions that explain what tests you’ve added, what they cover, and how to run them. We’ll explore PR templates that ensure consistency across your team.

Reviewing Test Code: You’ll learn what to look for when reviewing automated tests—not just syntax, but test design, coverage, maintainability, and reliability. We’ll cover tools like GitHub’s review interface and how to leave constructive, actionable feedback.

Addressing Feedback: You’ll practice the iterative process of updating your code based on review comments, pushing additional commits to the same PR, and having discussions right in the pull request interface.

Merging Changes: Once approved, you’ll learn different merge strategies (merge commit, squash, rebase) and when to use each for test automation code. We’ll also cover post-merge cleanup and branch deletion.

Resolving Merge Conflicts: We’ll tackle the inevitable conflicts that arise when multiple people modify shared test utilities, fixtures, or configuration files. You’ll learn how to safely resolve these conflicts without breaking existing tests.

Setting Up Branch Protection: You’ll configure rules that prevent direct pushes to main, require pull request reviews, and mandate that all tests pass before merging. These guardrails prevent accidents and maintain quality.

Automated Test Runs on PRs: Finally, you’ll set up CI/CD integration so that every pull request automatically runs your test suite. You’ll see results directly in the PR, making it easy to catch failures before they’re merged.

This lesson transforms you from a solo test automation developer into an effective team collaborator, ready to contribute to enterprise-scale testing projects with confidence.


Core Content

Core Content: Team Workflows: Pull Requests and Code Review for Test Automation

Core Concepts Explained

Understanding Pull Requests in Test Automation Context

A Pull Request (PR) is a workflow mechanism that allows team members to review and discuss code changes before merging them into the main codebase. For test automation, PRs are crucial because:

  • They ensure test quality through peer review
  • They catch test flakiness before it affects the team
  • They maintain consistent test patterns and standards
  • They provide a platform for knowledge sharing

The Pull Request Workflow

graph LR
    A[Create Feature Branch] --> B[Write/Update Tests]
    B --> C[Commit Changes]
    C --> D[Push to Remote]
    D --> E[Open Pull Request]
    E --> F[Code Review]
    F --> G{Approved?}
    G -->|Yes| H[Merge to Main]
    G -->|No| I[Address Feedback]
    I --> C

Setting Up Your Branch Strategy

Step 1: Create a feature branch

# Update your local main branch first
$ git checkout main
$ git pull origin main

# Create and switch to a new feature branch
$ git checkout -b feature/add-login-tests

# Verify you're on the new branch
$ git branch
  main
* feature/add-login-tests

Step 2: Make your test automation changes

Create a new test file or update existing tests:

// tests/login.spec.js
const { test, expect } = require('@playwright/test');

test.describe('Login Functionality', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('https://practiceautomatedtesting.com/login');
  });

  test('should successfully login with valid credentials', async ({ page }) => {
    // Arrange
    await page.fill('#username', 'testuser@example.com');
    await page.fill('#password', 'SecurePass123');
    
    // Act
    await page.click('#login-button');
    
    // Assert
    await expect(page).toHaveURL(/.*dashboard/);
    await expect(page.locator('.welcome-message')).toBeVisible();
  });

  test('should display error for invalid credentials', async ({ page }) => {
    // Arrange
    await page.fill('#username', 'invalid@example.com');
    await page.fill('#password', 'wrongpassword');
    
    // Act
    await page.click('#login-button');
    
    // Assert
    await expect(page.locator('.error-message')).toContainText('Invalid credentials');
    await expect(page).toHaveURL(/.*login/);
  });
});

Step 3: Commit your changes

# Check what files have changed
$ git status
On branch feature/add-login-tests
Untracked files:
  tests/login.spec.js

# Stage your changes
$ git add tests/login.spec.js

# Commit with a descriptive message
$ git commit -m "Add comprehensive login tests with valid and invalid scenarios"

# Push to remote repository
$ git push origin feature/add-login-tests

Creating a Pull Request

Step 4: Open the PR on your platform (GitHub/GitLab/Bitbucket)

<!-- SCREENSHOT_NEEDED: BROWSER
     URL: https://github.com/username/repo/compare/main...feature/add-login-tests
     Description: GitHub PR creation page showing branch comparison
     Placement: After push command explanation -->

PR Title Best Practices:

  • ✅ “Add login validation tests for positive and negative scenarios”
  • ✅ “Fix flaky checkout tests by adding explicit waits”
  • ❌ “Updated tests”
  • ❌ “Changes”

PR Description Template for Test Automation:

## Test Changes Summary
Brief description of what tests were added/modified

## Test Coverage
- [ ] Positive test scenarios
- [ ] Negative test scenarios
- [ ] Edge cases
- [ ] Cross-browser compatibility verified

## Test Execution Results
```bash
$ npm test

Running 15 specs...
✓ tests/login.spec.js (2 passed)
✓ tests/checkout.spec.js (5 passed)

15 passed (45s)

Closes #123

Review Checklist

  • Tests follow project naming conventions
  • No hardcoded waits (sleep/setTimeout)
  • Proper assertions used
  • Tests are independent and can run in any order

### Code Review Process for Test Automation

#### What to Look For as a Reviewer

**1. Test Independence and Reliability**

```javascript
// ❌ BAD: Test depends on previous test's state
test('should add item to cart', async ({ page }) => {
  await page.click('.add-to-cart');
  expect(await page.locator('.cart-count').textContent()).toBe('1');
});

test('should update cart count', async ({ page }) => {
  // Assumes cart already has 1 item from previous test
  await page.click('.add-to-cart');
  expect(await page.locator('.cart-count').textContent()).toBe('2');
});

// ✅ GOOD: Each test is independent
test('should add item to cart', async ({ page }) => {
  await page.goto('https://practiceautomatedtesting.com/products');
  await page.click('.add-to-cart');
  expect(await page.locator('.cart-count').textContent()).toBe('1');
});

test('should handle multiple items in cart', async ({ page }) => {
  await page.goto('https://practiceautomatedtesting.com/products');
  await page.click('.product-1 .add-to-cart');
  await page.click('.product-2 .add-to-cart');
  expect(await page.locator('.cart-count').textContent()).toBe('2');
});

2. Proper Wait Strategies

// ❌ BAD: Hardcoded waits
test('should submit form', async ({ page }) => {
  await page.click('#submit');
  await page.waitForTimeout(3000); // Arbitrary wait
  expect(await page.locator('.success')).toBeVisible();
});

// ✅ GOOD: Wait for specific conditions
test('should submit form', async ({ page }) => {
  await page.click('#submit');
  await page.waitForSelector('.success', { state: 'visible' });
  await expect(page.locator('.success')).toContainText('Form submitted successfully');
});

3. Clear Test Organization

// ✅ GOOD: Well-organized test structure
test.describe('Shopping Cart', () => {
  test.beforeEach(async ({ page }) => {
    // Common setup for all cart tests
    await page.goto('https://practiceautomatedtesting.com');
    await page.click('#clear-cart'); // Ensure clean state
  });

  test.describe('Adding Items', () => {
    test('should add single item', async ({ page }) => {
      // Test implementation
    });

    test('should add multiple items', async ({ page }) => {
      // Test implementation
    });
  });

  test.describe('Removing Items', () => {
    test('should remove item from cart', async ({ page }) => {
      // Test implementation
    });
  });
});

Providing Effective Review Feedback

Review Comment Examples:

// Original code in PR
test('login test', async ({ page }) => {
  await page.goto('https://practiceautomatedtesting.com/login');
  await page.fill('#user', 'test@test.com');
  await page.fill('#pass', 'password');
  await page.click('#btn');
});

Good Review Comments:

**Suggestion: Improve test naming and selectors**

The test name could be more descriptive. Consider:
- `test('should successfully login with valid email and password', ...)`

Also, the selectors might be fragile. Consider using data-testid attributes:
```javascript
await page.fill('[data-testid="username-input"]', 'test@test.com');
await page.fill('[data-testid="password-input"]', 'password');
await page.click('[data-testid="login-button"]');

This makes tests more maintainable when UI changes occur.


### Addressing Review Feedback

**Step 5: Update your PR based on feedback**

```bash
# Still on your feature branch
$ git checkout feature/add-login-tests

# Make the requested changes to your test files
# ... edit files ...

# Commit the changes
$ git add tests/login.spec.js
$ git commit -m "Address review feedback: improve selectors and test names"

# Push updates to the same branch
$ git push origin feature/add-login-tests

The PR will automatically update with your new commits.

Automated Checks in PRs

Setting up CI/CD to run tests automatically:

# .github/workflows/test.yml
name: Test Automation PR Check

on:
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      - name: Install dependencies
        run: npm ci
      - name: Run tests
        run: npm test
      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: test-results
          path: test-results/
<!-- SCREENSHOT_NEEDED: BROWSER
     URL: https://github.com/username/repo/pull/42/checks
     Description: PR checks showing test automation passing
     Placement: After CI/CD configuration -->

Merging the Pull Request

Step 6: Merge strategies

# After approval, you can merge via UI or command line

# Option 1: Merge commit (preserves all commits)
$ git checkout main
$ git merge --no-ff feature/add-login-tests

# Option 2: Squash merge (combines all commits into one)
$ git merge --squash feature/add-login-tests
$ git commit -m "Add login tests with comprehensive validation"

# Option 3: Rebase merge (linear history)
$ git checkout feature/add-login-tests
$ git rebase main
$ git checkout main
$ git merge feature/add-login-tests

Common Mistakes Section

1. Creating PRs That Are Too Large

Problem: PRs with 50+ test files and thousands of lines ✅ Solution: Break changes into smaller, focused PRs (e.g., one feature area at a time)

2. Not Running Tests Locally Before Pushing

Problem: Pushing broken tests that fail in CI

# Always run tests locally first
$ npm test
$ npm run lint

Solution: Create a pre-push git hook to run tests automatically

3. Vague PR Descriptions

Problem: “Fixed tests” with no context ✅ Solution: Use the PR template above with specific details about what changed and why

4. Ignoring Review Comments

Problem: Merging without addressing feedback or marking conversations as resolved ✅ Solution: Respond to each comment, either implementing the suggestion or explaining your approach

5. Force Pushing to Shared Branches

# ❌ NEVER do this on a branch others are reviewing
$ git push --force origin feature/add-login-tests

Solution: Use regular pushes or --force-with-lease if absolutely necessary

6. Not Updating Branch with Main

Problem: Your branch is 50 commits behind main, causing merge conflicts

# ✅ Regularly sync your branch
$ git checkout feature/add-login-tests
$ git fetch origin
$ git merge origin/main
# Or: git rebase origin/main

Debugging PR Issues

Issue: Tests pass locally but fail in CI

# Check CI logs for differences
# Common causes:
# 1. Different Node versions
# 2. Missing environment variables
# 3. Different browser versions

# Solution: Match your local environment to CI
$ nvm use 18.17.0  # Match CI Node version
$ npx playwright install --with-deps  # Ensure browsers match

Issue: Merge conflicts in test files

$ git checkout feature/add-login-tests
$ git fetch origin
$ git merge origin/main

# If conflicts occur:
# Auto-merging tests/login.spec.js
# CONFLICT (content): Merge conflict in tests/login.spec.js

# Open the file and resolve conflicts between <<<<<<< and >>>>>>>
# Then:
$ git add tests/login.spec.js
$ git commit -m "Resolve merge conflicts with main"
$ git push origin feature/add-login-tests

Hands-On Practice

EXERCISE AND CONCLUSION

🏋️ Hands-On Exercise

Exercise: Conduct a Complete PR Review Cycle for Test Automation

Scenario: You’re part of a QA automation team. A teammate has submitted a pull request adding Playwright tests for a login feature. Your task is to review the PR, provide feedback, and merge it following best practices.

Task Overview

Complete a full PR workflow cycle including creating a branch, submitting tests for review, reviewing another PR, addressing feedback, and merging.


Step-by-Step Instructions

Part 1: Create and Submit Your PR (30 minutes)

  1. Fork and clone the practice repository:

    git clone https://github.com/your-org/login-tests-practice
    cd login-tests-practice
    
  2. Create a feature branch:

    git checkout -b feature/add-password-reset-tests
    
  3. Write test automation code: Create tests/passwordReset.spec.js with at least 3 test cases for password reset functionality

  4. Commit with conventional commits:

    git add tests/passwordReset.spec.js
    git commit -m "test: add password reset validation tests"
    
  5. Push and create PR:

    git push origin feature/add-password-reset-tests
    
    • Write a descriptive PR title: Add password reset test automation
    • Fill out the PR template with:
      • What tests were added
      • Coverage details
      • Test execution results screenshot
      • Checklist completion

Part 2: Review a Teammate’s PR (20 minutes)

Review the provided sample PR (link in materials) and provide feedback on:

  1. Code Quality Check:

    • Are tests following Page Object Model pattern?
    • Are selectors robust (data-testid vs class names)?
    • Is there proper error handling?
  2. Test Design Review:

    • Do tests cover happy path and edge cases?
    • Are assertions meaningful and specific?
    • Is test data properly managed?
  3. Documentation Check:

    • Are test descriptions clear?
    • Is the PR description complete?
    • Are comments helpful but not excessive?
  4. Provide feedback using GitHub’s review features:

    • Add at least 2 inline comments
    • Request one specific change
    • Approve or request changes with summary comment

Part 3: Address Review Feedback (15 minutes)

  1. Respond to comments on your PR:

    • Address each review comment
    • Make requested changes
    • Push updates to your branch
  2. Request re-review:

    • Tag reviewers after changes
    • Add comment summarizing what was fixed

Part 4: Merge and Cleanup (10 minutes)

  1. Final checks:

    • Ensure CI/CD pipeline passes
    • Verify all conversations resolved
    • Get required approvals
  2. Merge the PR:

    • Choose appropriate merge strategy (squash recommended)
    • Delete the branch after merge
  3. Verify in main branch:

    git checkout main
    git pull origin main
    npm test -- tests/passwordReset.spec.js
    

Expected Outcome

By the end of this exercise, you should have:

✅ Created a well-structured PR with comprehensive test automation code
✅ Written a clear PR description following team templates
✅ Conducted a thorough code review with constructive feedback
✅ Responded professionally to review comments
✅ Successfully merged tests into the main branch
✅ Verified the complete CI/CD pipeline execution


Starter Code

Sample PR Template:

## Description
<!-- What tests does this PR add/modify? -->

## Test Coverage
- [ ] Happy path scenarios
- [ ] Error handling
- [ ] Edge cases
- [ ] Cross-browser testing

## Test Execution Results
<!-- Add screenshot or test report -->

## Checklist
- [ ] Tests follow team conventions
- [ ] Page objects updated
- [ ] Test data externalized
- [ ] All tests passing locally
- [ ] Documentation updated

Sample Test Structure:

// tests/passwordReset.spec.js
import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';

test.describe('Password Reset Flow', () => {
  test('should display reset password link', async ({ page }) => {
    const loginPage = new LoginPage(page);
    await loginPage.navigate();
    // TODO: Complete test implementation
  });

  test('should send reset email for valid user', async ({ page }) => {
    // TODO: Implement
  });

  test('should show error for non-existent email', async ({ page }) => {
    // TODO: Implement
  });
});

Solution Approach

For PR Creation:

  • Use descriptive branch names (feature/, bugfix/, test/)
  • Write atomic commits with clear messages
  • Complete all checklist items before requesting review
  • Include evidence of test execution (screenshots/reports)

For Code Review:

  • Review systematically: structure → logic → style → documentation
  • Be specific and actionable in feedback
  • Balance criticism with positive recognition
  • Focus on learning and improvement, not just finding issues

For Addressing Feedback:

  • Respond to every comment (even if just acknowledging)
  • Ask clarifying questions if feedback is unclear
  • Make changes in separate commits for easy tracking
  • Re-request review after addressing major concerns

🎓 Key Takeaways

What You Learned

🔑 PR Best Practices for Test Automation

  • Structure PRs to focus on specific test scenarios or features
  • Use conventional commits and clear descriptions to make test changes traceable
  • Include test execution evidence and coverage metrics in PR descriptions

🔑 Effective Code Review for Tests

  • Review test code for maintainability, not just functionality
  • Check for proper test patterns (AAA, Page Objects) and robust selectors
  • Verify comprehensive coverage including edge cases and error scenarios

🔑 Collaborative Workflow Management

  • Use GitHub’s review features (inline comments, suggestions, approval states) to facilitate async communication
  • Respond constructively to feedback and iterate on test improvements
  • Ensure CI/CD integration validates tests automatically before merge

🔑 Quality Gates and Merge Strategies

  • Enforce required checks (passing tests, code coverage, approvals) before merging
  • Choose appropriate merge strategies (squash for clean history)
  • Clean up branches and verify integration after merge

When to Apply These Skills

  • Daily: Reviewing teammate PRs and submitting your own test code
  • Sprint Planning: Setting up PR templates and review guidelines for test automation
  • CI/CD Setup: Configuring automated checks and quality gates
  • Team Onboarding: Teaching new team members the PR workflow
  • Quality Audits: Ensuring consistent test code quality across the team

🚀 Next Steps

What to Practice

  1. Increase review depth: Practice reviewing 5-10 PRs, focusing on different aspects each time (security, performance, accessibility testing)
  2. Refine your PR skills: Submit progressively complex test PRs (API tests, visual regression, E2E flows)
  3. Automate checks: Set up GitHub Actions to run linters, type checkers, and test coverage reports on your PRs
  4. Template creation: Develop custom PR templates for different test types (unit, integration, E2E)
  • Advanced Git Workflows: Rebase vs merge strategies, conflict resolution in test code
  • CI/CD Deep Dive: Parallel test execution, flaky test detection, test result reporting
  • Trunk-Based Development: Fast-paced merge strategies for test automation teams
  • Automated Code Review Tools: SonarQube, CodeClimate for test code quality
  • Cross-Team PR Practices: Working with development teams on testability improvements
  • Test Impact Analysis: Running only affected tests based on code changes
  • GitHub Skills: “Review pull requests” interactive course
  • Martin Fowler’s article on “Continuous Integration”
  • “Accelerate” by Nicole Forsgren (Chapter on trunk-based development)
  • Your team’s contribution guidelines and style guides

Remember: Great PR workflows create better test code through collaboration. The goal isn’t perfection—it’s continuous improvement through constructive peer review! 🎯