---
title: Testing & Continuous Integration
description: How Wails v3 ensures quality with unit tests, integration suites, race detection, and GitHub Actions CI.
sidebar:
  order: 9
---

Robust desktop frameworks demand rock-solid testing.  
Wails v3 employs a **layered strategy**:

| Layer | Goal | Tooling |
|-------|------|---------|
| Unit tests | Fast feedback for isolated functions | `go test ./...` |
| Integration / Example tests | Validate whole features across packages | Example apps + headless assertions |
| Race detection | Catch data races in the runtime & bridge | `go test -race`, `wails3 dev -race` |
| CI matrix | Cross-OS confidence on every PR | GitHub Actions |

This document explains **where tests live**, **how to run them**, and **what happens in CI**.

---

## 1. Directory Conventions

```
v3/
├── internal/.../_test.go     # Unit tests for internal packages
├── pkg/.../_test.go          # Public API tests
├── examples/...              # Example apps double as integration tests
├── tasks/events/...          # Generated code tests run in CI
└── pkg/application/RACE.md   # Race test guidance & known safe suppressions
```

Guidelines:

* **Keep unit tests next to code** (`foo.go` ↔ `foo_test.go`)
* Use the **black-box style** for `pkg/` packages (`package application_test`)
* Integration helpers go in `internal/testutil/` (shared mocks, fixtures)

---

## 2. Unit Tests

### Writing Tests

```go
func TestColourParseHex(t *testing.T) {
    c, err := colour.Parse("#FF00FF")
    require.NoError(t, err)
    assert.Equal(t, 255, c.R)
}
```

Recommendations:

* Use [`stretchr/testify`](https://github.com/stretchr/testify) – already vendor-imported.
* Follow **table-driven** style for branches.
* Stub platform quirks behind build tags (`_test_windows.go` etc.) when needed.

### Running Locally

```bash
cd v3
go test ./... -cover
```

Taskfile shortcut:

```
task test          # same as above + vet + lint
```

---

## 3. Integration & Example Tests

Every folder under `v3/examples/` is a **self-contained app**.  
Three techniques turn them into tests:

| Technique | File | What it checks |
|-----------|------|----------------|
| `go test ./...` inside example | `*_test.go` spins up `wails dev` in headless mode | Build & startup |
| CLI golden tests | `internal/commands/appimage_test.go` | Generated artefact hashes |
| Scripted e2e | `tasks/events/generate.go` | Emits Go that launches example, asserts runtime logs |

Run all with:

```
task integration
```

> Headless mode uses **Xvfb** on Linux runners; macOS & Windows start minimized.

---

## 4. Race Detection

Data races are fatal in GUI runtimes.

### Dedicated Doc

See `v3/pkg/application/RACE.md` for:

* Known benign races and suppression rationale
* How to interpret stack-traces crossing Cgo boundaries

### Local Race Suite

```
go test -race ./...
```

or

```
wails3 dev -race
```

*The latter rebuilds runtime with race flags and launches a demo window.  
Close the window; any races print after exit.*

CI runs the race suite on **linux/amd64** (fastest) for every PR.

---

## 5. GitHub Actions Workflows

### 5.1 `build-and-test-v3.yml`

Location: `.github/workflows/build-and-test-v3.yml`

Key features:

* **Matrix** over `os: [ubuntu-latest, windows-latest, macos-latest]`
* Caches Go & npm deps for speed
* Steps:
  1. `setup-go` @ 1.25
  2. `go vet ./...`
  3. `go test ./... -v -coverprofile=cover.out`
  4. Build CLI + sample app (`wails3 build -skip-package`)
  5. Upload coverage to Codecov
* Conditional **race** job on Ubuntu:
  ```yaml
  - name: Race Detector
    if: matrix.os == 'ubuntu-latest'
    run: go test -race ./...
  ```

### 5.2 Static Analysis

* `semgrep.yml` – security/lint scanning (`.github/workflows/semgrep.yml`)
* `qodana.yaml` – JetBrains Qodana cloud inspection (optional in PR)

### 5.3 Release Pipeline

`runtime.yml` builds and publishes the JS runtime to npm on tag push; out of testing scope but referenced by build matrix.

---

## 6. Local CI Parity

Run the **exact** CI task set via Taskfile:

```
task ci
```

It executes:

1. `lint` (golangci-lint, govet)
2. `test` (unit + race)
3. `integration`
4. `build` (for host platform)

---

## 7. Troubleshooting Failing Tests

| Symptom | Likely Cause | Fix |
|---------|--------------|-----|
| **Race in `runtime_darwin.go`** | Forgot to lock `mainthread.Call` | Use `mainthread.Sync` helper |
| **Windows headless hangs** | Console window waiting for input | Pass `-verbose` and ensure no dialogs open |
| **CI example build fails** | Template changed without bumping example deps | `task update-examples` regenerates lockfiles |
| **Coverpkg errors** | Integration test importing `main` | Switch to build tags `//go:build integration` |

---

## 8. Adding New Tests

1. **Unit** – create `*_test.go`, run `go test ./...`
2. **Integration** – update or add example app + test harness
3. **CI** – commit; the workflow auto-discovers tests  
   If OS-specific, add skip tags:

```go
//go:build !windows
```

---

## 9. Key File Map

| What | Path |
|------|------|
| Unit test example | `internal/colour/colour_test.go` |
| Integration harness | `internal/commands/appimage_test.go` |
| Race guide | `pkg/application/RACE.md` |
| Taskfile test targets | `v3/Taskfile.yaml` |
| CI workflow | `.github/workflows/build-and-test-v3.yml` |

---

Quality isn’t an afterthought in Wails v3.  
With unit tests, integration suites, race detection, and a cross-platform CI
matrix you can contribute confidently, knowing your changes run green on every
OS we support.  
Happy testing!
