# no-mistakes Test Suite Structure and E2E Test Organization

> Discover the no-mistakes test suite structure for Go. Learn how to organize fast unit, integration, and e2e tests with clear separation and build tag guarding.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: architecture
- Published: 2026-07-16

---

**The no-mistakes repository uses a three-layer Go testing strategy that isolates fast unit tests from integration tests and full end-to-end (e2e) tests, with the latter guarded by the `e2e` build tag and located in `internal/e2e/`.**

The `kunchenguid/no-mistakes` project implements a rigorous testing architecture designed to balance development velocity with comprehensive validation. Understanding the **no-mistakes test suite structure** reveals how the project maintains code quality through strategic separation of concerns, from isolated function tests in `*_test.go` files to complete user journey simulations that drive the full CLI and daemon stack.

## Three-Layer Test Architecture

The repository organizes tests into distinct layers based on execution speed and scope. This separation ensures that developers receive rapid feedback during iterative development while still maintaining a thorough safety net for release candidates.

### Unit and Package Tests

Unit tests validate individual functions, helpers, and small components in isolation. These files follow Go conventions by using the `*_test.go` suffix and are distributed throughout the repository alongside the code they exercise.

Examples of unit test locations include [`internal/intent/intent_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/intent_test.go) for intent extraction logic and [`internal/wizard/view_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/wizard/view_test.go) for UI component validation. These tests run quickly and execute by default when invoking `go test ./...` without any build tags.

### Integration Tests

Integration tests verify interactions between a small set of packages, such as pipeline steps or daemon lock handling. While still executed by the standard test command, these tests may spin up temporary processes or require more elaborate setup than pure unit tests.

Key integration test files include [`internal/daemon/lock_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/lock_test.go), which validates the singleton lock semantics critical to daemon operation, and [`internal/pipeline/steps/steps_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/steps_test.go), which ensures that pipeline step composition behaves correctly. These files do not use build tags but remain distinct from e2e tests due to their limited scope.

### End-to-End (E2E) Tests

E2E tests drive the complete CLI, daemon, and agent stack against real Git repositories to verify full user journeys, including hooks, database persistence, and agent-generated prompts. These tests reside in `internal/e2e/*.go` and are excluded from default test runs to prevent slowing down standard development workflows.

## How E2E Tests Are Organized

The e2e layer follows strict organizational patterns to ensure consistency and isolation across complex test scenarios.

### Build Tag Isolation

Every e2e file begins with the header `//go:build e2e`, which prevents the Go toolchain from compiling these tests unless explicitly requested. This isolation ensures that `go test ./...` only runs fast unit and integration tests, while the e2e suite executes only when triggered with the `e2e` build tag.

For example, [`internal/e2e/journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/e2e/journey_test.go) starts with this build constraint, as do specialized scenario files like [`internal/e2e/intent_journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/e2e/intent_journey_test.go), [`internal/e2e/fork_routing_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/e2e/fork_routing_test.go), [`internal/e2e/daemon_run_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/e2e/daemon_run_test.go), and [`internal/e2e/axi_journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/e2e/axi_journey_test.go).

### The Shared Test Harness

All e2e tests instantiate a reusable `harness` struct defined in [`internal/e2e/harness_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/e2e/harness_test.go). This harness provides a clean environment for each test by creating a temporary Git repository, a fresh `NM_HOME` directory, and a managed daemon process.

```go
// internal/e2e/harness_test.go
type harness struct {
    RepoRoot string
    NMHome   string
    Daemon   *exec.Cmd
    // …helpers for git, waiting for runs, etc.
}

```

The harness abstracts away environment setup, allowing test authors to focus on scripting realistic workflows rather than managing process lifecycle details.

### Scenario-Based Test Files

Each e2e test file scripts a specific realistic workflow. For instance, [`internal/e2e/journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/e2e/journey_test.go) demonstrates a complete review journey by creating branches, pushing to the gate, and asserting on daemon behavior:

```go
featureHead := h.CommitChange("feature/e2e", "hello.txt", "hello world\n", "add hello.txt")
h.PushToGate("feature/e2e")
activeRun := h.WaitForRunRunning("feature/e2e", 30*time.Second)
// …assert prompts, findings, and final run status

```

Specialized scenario files include:
- **[`intent_journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/intent_journey_test.go)** – Validates intent extraction and provenance tracking
- **[`fork_routing_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/fork_routing_test.go)** – Verifies pull-request fork handling logic
- **[`daemon_run_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/daemon_run_test.go)** – Confirms daemon startup and shutdown semantics in e2e mode
- **[`axi_journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/axi_journey_test.go)** – Exercises the `axi` CLI shortcuts through end-to-end flows

Some tests dynamically write temporary helper binaries (such as a fake `nm-test-e2e` executable) using `os.WriteFile` to simulate user-defined test or lint commands without requiring external dependencies.

## Running E2E Tests in no-mistakes

The repository's `Makefile` defines a dedicated target for executing the e2e suite:

```make
e2e: ## run end‑to‑end tests

	go test -tags=e2e ./internal/e2e -count=1 -p 1

```

The `-p 1` flag ensures tests run serially because the daemon uses a singleton lock mechanism that prevents concurrent instances. The `-count=1` flag disables test caching to guarantee fresh execution. Developers can invoke this target using `make e2e` or run the underlying `go test` command directly with the `e2e` build tag.

## Summary

- The **no-mistakes test suite** separates concerns into unit tests (fast, distributed), integration tests (multi-package interactions), and e2e tests (full stack).
- E2E tests live in `internal/e2e/` and require the `//go:build e2e` tag to execute.
- The `harness` struct in [`internal/e2e/harness_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/e2e/harness_test.go) provides isolated Git repositories and daemon processes for each test.
- Scenario files like [`journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/journey_test.go) and [`intent_journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/intent_journey_test.go) script realistic user workflows including branch creation, gate pushes, and run monitoring.
- Execute e2e tests via `make e2e`, which runs `go test -tags=e2e ./internal/e2e -count=1 -p 1` to ensure serial execution and fresh builds.

## Frequently Asked Questions

### What build tag is required to run no-mistakes e2e tests?

You must use the `e2e` build tag. All e2e source files in `internal/e2e/` begin with `//go:build e2e`, so you need to run `go test -tags=e2e ./internal/e2e` to compile and execute them. Without this tag, the Go toolchain skips these files entirely.

### Where are the e2e tests located in the no-mistakes repository?

End-to-end tests reside in the `internal/e2e/` directory. Key files include [`journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/journey_test.go) for main user flows, [`harness_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/harness_test.go) for shared test infrastructure, and specialized scenario files such as [`intent_journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/intent_journey_test.go) and [`axi_journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/axi_journey_test.go).

### How does the e2e test harness create isolated environments?

The `harness` struct defined in [`internal/e2e/harness_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/e2e/harness_test.go) programmatically creates temporary directories for Git repositories and `NM_HOME`, then manages a daemon subprocess. Each test instantiates a fresh harness, ensuring that repository state, database files, and process state do not leak between test cases.

### Why do e2e tests run with `-p 1` in the Makefile?

The `-p 1` flag restricts test execution to a single process at a time. This is necessary because the no-mistakes daemon acquires a singleton file lock to prevent multiple instances from running concurrently. Parallel test execution would cause lock contention and test failures, so the Makefile explicitly serializes the e2e suite.