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)
Related Issue
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)
-
Fork and clone the practice repository:
git clone https://github.com/your-org/login-tests-practice cd login-tests-practice
-
Create a feature branch:
git checkout -b feature/add-password-reset-tests
-
Write test automation code: Create
tests/passwordReset.spec.js
with at least 3 test cases for password reset functionality -
Commit with conventional commits:
git add tests/passwordReset.spec.js git commit -m "test: add password reset validation tests"
-
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
- Write a descriptive PR title:
Part 2: Review a Teammate’s PR (20 minutes)
Review the provided sample PR (link in materials) and provide feedback on:
-
Code Quality Check:
- Are tests following Page Object Model pattern?
- Are selectors robust (data-testid vs class names)?
- Is there proper error handling?
-
Test Design Review:
- Do tests cover happy path and edge cases?
- Are assertions meaningful and specific?
- Is test data properly managed?
-
Documentation Check:
- Are test descriptions clear?
- Is the PR description complete?
- Are comments helpful but not excessive?
-
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)
-
Respond to comments on your PR:
- Address each review comment
- Make requested changes
- Push updates to your branch
-
Request re-review:
- Tag reviewers after changes
- Add comment summarizing what was fixed
Part 4: Merge and Cleanup (10 minutes)
-
Final checks:
- Ensure CI/CD pipeline passes
- Verify all conversations resolved
- Get required approvals
-
Merge the PR:
- Choose appropriate merge strategy (squash recommended)
- Delete the branch after merge
-
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
- Increase review depth: Practice reviewing 5-10 PRs, focusing on different aspects each time (security, performance, accessibility testing)
- Refine your PR skills: Submit progressively complex test PRs (API tests, visual regression, E2E flows)
- Automate checks: Set up GitHub Actions to run linters, type checkers, and test coverage reports on your PRs
- Template creation: Develop custom PR templates for different test types (unit, integration, E2E)
Related Topics to Explore
- 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
Recommended Resources
- 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! 🎯