DEV Community

Cover image for What is GitHub Actions Matrix Strategy?
Serhat Ozdursun
Serhat Ozdursun

Posted on

What is GitHub Actions Matrix Strategy?

The GitHub Actions matrix strategy is a powerful feature that allows you to run the same job across multiple combinations of variables—like environments, operating systems, or software versions—without duplicating code. It's ideal for scenarios such as:

  • Testing across different browser environments
  • Running code against multiple versions of a language
  • Deploying across multiple platforms (e.g., Android and iOS)

By using a strategy.matrix section in your workflow, you can define all the variations you want to test or execute. GitHub will then automatically create a job for each combination. This not only helps keep workflows clean and scalable, but also provides a clear view of which combinations succeed or fail.

For example:

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest]
    node: [16, 18]
Enter fullscreen mode Exit fullscreen mode

This configuration will run four jobs in parallel:

  • Ubuntu + Node 16
  • Ubuntu + Node 18
  • Windows + Node 16
  • Windows + Node 18

Learn more in the official GitHub Docs

Cross-Browser UI Testing with GitHub Actions Matrix Strategy

When building UI automation workflows, one of the most common challenges is ensuring consistent functionality across different browsers. Initially, I handled this by creating separate GitHub Actions YAML files for each browser:

  • ui_chrome_pytest.yml
  • ui_firefox_pytest.yml

Each file had almost identical steps, with only minor differences:

🔍 Key Differences in the Old Files

ui_chrome_pytest.yml manually installs Google Chrome and ChromeDriver.

ui_firefox_pytest.yml uses the browser-actions/setup-firefox action for Firefox and GeckoDriver.

The pytest command uses --browser chrome in one and --browser firefox in the other.

Both upload the same artifacts, but the file names are not browser-specific (they would overwrite each other if run together).

This setup worked, but had several downsides:

  • ❌ Duplication of logic: Every change had to be applied in multiple files.
  • ❌ Error-prone: It’s easy to forget updating one file.
  • ❌ Scalability issues: Adding more browsers or platforms meant creating even more nearly-identical files.

The Solution: Matrix Strategy

So, to eliminate the duplication and better manage different browser setups, I leveraged the GitHub Actions matrix strategy. This approach allows each browser to be tested in parallel, using a single, unified workflow file.

To solve this, I created a new GitHub Actions workflow using a matrix strategy that dynamically switches between browsers:

ui_cross_browser_test.yml

name: UI Automation Tests

on:
  pull_request:
    branches:
      - main

jobs:
  build_and_test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        browser: [chrome, firefox] # Matrix used to define browsers to test

    steps:
      - name: Checkout resume repository
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22'

      - name: Install dependencies and build
        run: |
          yarn install
          yarn build

      - name: Start the application
        run: |
          yarn start &
        env:
          PORT: 3000

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      # Chrome-specific installation
      - name: Install Chrome and ChromeDriver
        if: matrix.browser == 'chrome'
        run: |
          sudo apt update
          sudo apt install -y wget gnupg
          wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
          sudo apt install -y ./google-chrome-stable_current_amd64.deb
          CHROMEDRIVER_VERSION=$(curl -sS https://chromedriver.storage.googleapis.com/LATEST_RELEASE)
          wget https://chromedriver.storage.googleapis.com/${CHROMEDRIVER_VERSION}/chromedriver_linux64.zip
          unzip chromedriver_linux64.zip
          sudo mv chromedriver /usr/local/bin/chromedriver
          sudo chmod +x /usr/local/bin/chromedriver

      # Firefox-specific setup using reusable action
      - name: Set up Firefox and GeckoDriver
        if: matrix.browser == 'firefox'
        uses: browser-actions/setup-firefox@latest

      - name: Clone the test repository
        run: |
          git clone https://github.com/serhatozdursun/serhatozdursun-ui-tests.git
        env:
          GITHUB_TOKEN: ${{ secrets.UI_TEST_TOKEN }}

      - name: Install Python dependencies
        working-directory: serhatozdursun-ui-tests
        run: |
          pip install -r requirements.txt

      # Matrix-aware pytest command
      - name: Run tests on ${{ matrix.browser }}
        working-directory: serhatozdursun-ui-tests
        id: run_tests
        run: |
          pytest --browser ${{ matrix.browser }} --base_url http://localhost:3000 --html=reports/html/report.html --junitxml=reports/report.xml

      - name: Upload HTML report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: html-report-${{ matrix.browser }}
          path: serhatozdursun-ui-tests/reports/html
          retention-days: 5
        continue-on-error: true

      - name: Upload XML report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: xml-report-${{ matrix.browser }}
          path: serhatozdursun-ui-tests/reports/report.xml
          retention-days: 5
        continue-on-error: true
Enter fullscreen mode Exit fullscreen mode

View the full workflow file

Before vs After

Approach Pros Cons
Separate files Easy to isolate logic Repetitive, hard to scale
Matrix strategy Clean, DRY, scalable, browser-aware Slightly more complex YAML logic

Final Thoughts

Using GitHub Actions' matrix strategy is a game-changer for cross-browser testing. If you're managing separate workflows per browser, consolidating them will make your CI setup much more efficient.

Stay sharp, test smart! 🚀🧪

Connect with me on GitHub: serhatozdursun.com

Top comments (0)