Running UI Automation Tests with Go and Chrome on GitHub Actions

Pradap Pandiyan
5 min readOct 2, 2024

--

Automating UI tests is an essential part of modern software development. If you’re using Go for your test automation, you can easily integrate it into a CI/CD pipeline with GitHub Actions. In this article, we will walk through how to set up a GitHub Actions workflow to run UI tests in headless mode using Chrome and Go.

r

Prerequisites

  • Go programming language
  • GitHub Actions for continuous integration

The Problem

When running UI automation tests locally, you can execute them in a headed mode (i.e., with the browser’s UI visible). However, on a CI server (like GitHub Actions), there is no graphical interface (GUI). To handle this, you need to run the tests in headless mode, where Chrome operates without rendering a graphical interface.

Solution

We’ll set up a GitHub Actions workflow that:

  1. Installs dependencies, including Go and Google Chrome.
  2. Runs your Go-based UI tests using Chrome in headless mode.
  3. Uses xvfb-run to simulate a virtual framebuffer, enabling Chrome to run in headless environments.

Project Setup

In this example, let’s assume you have a Go project with some UI automation tests written using chromedp—a headless Chrome/Chromium driver for Go.

Here is a simplified version of what your Go test might look like:

Example Go Code (Headless Mode)

package main
import (
"context"
"fmt"
"log"
"os"
"strings"
"time"
"github.com/chromedp/chromedp"
"github.com/chromedp/chromedp/kb"
)
func main() {
// Check environment variable for headless mode
headless := os.Getenv("HEADLESS") != "false"
// Set Chrome options
opts := chromedp.DefaultExecAllocatorOptions[:]
opts = append(opts,
chromedp.Flag("headless", headless), // Headless mode toggle
chromedp.Flag("disable-gpu", true), // Disable GPU in headless mode
chromedp.Flag("no-sandbox", true), // Disable sandbox
)
allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
defer cancel()
ctx, cancel := chromedp.NewContext(allocCtx)
defer cancel()
// Set timeout
ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
defer cancel()
var result string
// Run automation tasks
err := chromedp.Run(ctx,
chromedp.Navigate("https://www.google.com"),
chromedp.WaitVisible(`//textarea[@name="q"]`),
chromedp.SendKeys(`//textarea[@name="q"]`, "Golang"),
chromedp.SendKeys(`//textarea[@name="q"]`, kb.Enter),
chromedp.WaitVisible(`#search`),
chromedp.Text(`#search`, &result),
)
if err != nil {
log.Fatal(err)
}
if strings.Contains(result, "Golang") {
fmt.Println("Test Passed: 'Golang' found in search results")
} else {
fmt.Println("Test Failed: 'Golang' not found in search results")
}
}

GitHub Actions Workflow

To run these UI automation tests on GitHub Actions, we need to create a .yml file in the .github/workflows directory of your repository. Below is the full workflow configuration.

GitHub Actions YAML File

name: Go UI Automation Tests
on: [push] # Trigger the workflow on code push
jobs:
build:
runs-on: ubuntu-latest # Use the latest Ubuntu environment
steps:
# Step 1: Check out the code from your repository
- uses: actions/checkout@v4
# Step 2: Set up Go
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.21.x' # Use Go 1.21.x
# Step 3: Install Go dependencies
- name: Install dependencies
run: go get .
# Step 4: Install Chrome and other dependencies
- name: Install Chrome dependencies
run: |
sudo apt-get update
sudo apt-get install -y wget gnupg
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
sudo apt-get update
sudo apt-get install -y google-chrome-stable
# Step 5: Run the UI tests in headless mode using xvfb-run
- name: Run UI Tests in Headless Mode
env:
CHROME_BIN: /usr/bin/google-chrome # Set Chrome binary path
run: |
xvfb-run --auto-servernum go test -v ./...

Explanation of Workflow Steps

  1. Check out the code: The actions/checkout step checks out your repository's code so the tests can run against it.
  2. Set up Go: The actions/setup-go step installs Go version 1.21.x on the runner.
  3. Install Go dependencies: The go get command fetches and installs any required Go packages, ensuring your test environment is ready.
  4. Install Chrome: This step installs Google Chrome in the GitHub Actions runner. We use apt-get to install Chrome's dependencies, add Chrome’s signing key, and install Chrome stable.
  5. Run tests using xvfb-run: Since Chrome requires a display (even in headless mode), we use xvfb-run, which provides a virtual X server for Chrome to run in. This allows the headless tests to execute successfully without a physical display.

Why Use xvfb-run?

xvfb-run simulates a display for programs that require a graphical user interface (GUI), such as Chrome. Even when running in headless mode, Chrome sometimes needs a display server for certain operations, and xvfb (X Virtual Framebuffer) helps in this scenario.

Running Tests Locally vs. On GitHub Actions

Running Locally (Headed Mode)

When running tests on your local machine, you might want to see the browser. You can run Chrome in headed mode by setting the HEADLESS environment variable to false:

HEADLESS=false go test -v

This allows you to run the tests with a visible browser window for easier debugging.

Running on GitHub Actions (Headless Mode)

In the GitHub Actions workflow, headless mode is enforced by default. You do not need to set the HEADLESS environment variable explicitly, as Chrome will run in headless mode when no display is detected.

Conclusion

Integrating UI automation tests written in Go with GitHub Actions is straightforward when using Chromedp and xvfb to handle headless browser operations. By using a well-configured GitHub Actions workflow, you can automate and test your application’s UI effectively in a CI/CD pipeline. With Chrome in headless mode and xvfb to handle display dependencies, your tests will run smoothly even in non-GUI environments like GitHub Actions.

This setup ensures that your tests work locally in headed mode while seamlessly running in headless mode in CI, giving you the flexibility and reliability needed for UI test automation.

I have created a project on GitHub and added the code here.

Feel free to hit clap if you like the content. Happy Automation Testing :) Cheers. 👏

--

--

Pradap Pandiyan

I’m a passionate QA Engineer. I’m a motovlogger, content creator, off-roader and freelancer. Buy me a coffee here https://www.buymeacoffee.com/pradappandiyan