The Tesults web app is designed for desktop browsers. Sign up and configure your project on a laptop or desktop. Use the iOS app or Android app to view results on the go.

How to Report Go Test Results to a Dashboard

Go has no reporter plugin, so reporting go test results means parsing go test -json and uploading the cases yourself. Here is the whole pattern.

blog-title-image

Unlike Playwright or Jest, Go has no reporter plugin you drop into a config file. Reporting go test results to a dashboard is a two step pattern instead: run go test -json to get structured output, turn each event into a test case, and upload the cases with the Tesults Go library by calling tesults.Results(data). Once that runs on each CI build, your Go results are stored in a dashboard the team can open, retained across runs, with suites, durations, and failure reasons attached. This post walks the whole pattern, because with Go you assemble it yourself rather than installing a reporter.

Why is Go different from Jest or Playwright here?

Frameworks like Jest and Playwright expose a reporter interface, so a plugin can hook in, watch every test as it runs, and push results with no work from you. Go's testing package has no such interface. There is no reporter plugin to install, and no hook to register.

What Go gives you instead is go test -json, a structured stream of events describing the run. That is the raw material. So reporting Go results is not "install a plugin", it is "parse the JSON stream into test cases and upload them". The Tesults Go library handles the upload half cleanly. The parsing half is yours, and it is the part worth getting right, so most of this post is about that.

How do you get structured output from go test?

Run your tests with the -json flag:

go test -json ./... > results.json

Rather than the usual human readable output, this emits one JSON object per line, an event stream. Each line has an Action such as run, pass, fail, or output, and identifies the Package and, for test level events, the Test name. The events you care about for reporting are the terminal ones for each test: the pass, fail, or skip action that tells you how a given test finished, along with its Elapsed time.

You can pipe this straight into a small uploader program, or write results.json in one CI step and process it in the next. Either works. The point is that -json is what turns Go's output from text you read into data you can map to test cases.

How do you turn that into Tesults test cases?

Install the library:

go get github.com/tesults/go

Import it where you do the upload:

import (
    "github.com/tesults/go/tesults"
)

The library uploads a single data map that contains your target token and a list of cases. Each case is a map with, at minimum, a name and a result of pass, fail, or unknown. Everything else is optional but valuable: suite to group cases, desc, reason for why a failure happened, start and end timestamps, and files. Here is the shape:

data := map[string]interface{}{
    "target": "token",
    "results": map[string]interface{}{
        "cases": []interface{}{
            map[string]interface{}{
                "name": "TestSubmitOrder",
                "suite": "Checkout",
                "result": "fail",
                "reason": "Assert fail in line 203 of checkout_test.go",
            },
            map[string]interface{}{
                "name": "TestLoadHomepage",
                "suite": "Navigation",
                "result": "pass",
            },
        },
    },
}

In practice you do not hand write these. You loop over the events you parsed from go test -json and build one case map per test, mapping the Go action to a Tesults result: a pass action becomes "pass", a fail becomes "fail", and a skip is usually reported as "unknown". The Go package name is a natural fit for suite, which groups your cases the way your code is already organised. For failures, capture the test's output lines and put them in reason so the dashboard shows why it failed, not just that it did.

How do you upload and confirm it worked?

Pass the data map to Results:

res := tesults.Results(data)

fmt.Println("Success:", res["success"])
fmt.Println("Message:", res["message"])

The return value is a map worth checking rather than ignoring. res["success"] is a bool, and when it is false, res["message"] tells you why the upload failed, which is where you will catch a missing token or a required field left empty. res["warnings"] is a slice of strings that is non empty when there were problems with file uploads specifically, so a run can succeed overall while still warning that a screenshot did not make it. In a CI step, checking success and printing message on failure saves you from a build that silently uploaded nothing.

How do you attach durations, steps, and files?

Since you are building the case maps yourself, the richer fields are just more keys. Provide start and end as milliseconds since the Unix epoch and Tesults calculates duration for you, no need to compute it:

map[string]interface{}{
    "name": "TestSubmitOrder",
    "suite": "Checkout",
    "result": "pass",
    "start": startMillis,
    "end": endMillis,
    "files": []string{"/full/path/to/log.txt", "/full/path/to/screencapture.png"},
}

The Elapsed value from the -json stream gives you what you need to populate these. Attach artifacts with files, a slice of absolute paths, and they are uploaded and shown on the case. You can also add steps for a sequence of sub actions within a test, and any custom field by prefixing its key with an underscore, for example "_Environment": "staging". One caution from the docs: file upload time depends entirely on your network speed and the upload blocks at the end, so attach a reasonable number of files per case, and when first integrating, get results uploading without files to confirm the setup before adding them.

How do you report the build and consolidate parallel runs?

To record the build itself, add one more case to the array with its suite set to [build]. That entry is treated as build metadata rather than a test case, and takes a name (the version or revision), a result, and optionally a desc and reason:

map[string]interface{}{
    "name": "2.4.1",
    "suite": "[build]",
    "result": "pass",
    "desc": "checkout refactor",
}

If you shard your Go tests across parallel CI jobs, each job calls Results separately and Tesults records each as its own run by default. Give every job the same build name and enable Build Consolidation from the configuration menu, and submissions sharing that name merge into one run automatically. If there is no natural version to use, a timestamp captured when the run starts works as the shared identifier.

The pattern is the whole answer: go test -json for structured output, a loop that maps each result into a case with its package as the suite and its failure output as the reason, and one tesults.Results call to upload. Because Go hands you the events rather than a reporter, you control exactly what gets reported, and once it runs in CI your Go results become a retained, team visible history instead of console output that scrolls away. The full library reference, every test case and build property, is in the Tesults Go documentation.

Test automation reporting and failure intelligence

Consolidated test reporting for engineering teams. Store, track, and understand test results across every run and system.

Latest Posts

How to Report Go Test Results to a Dashboard
How to Report Go Test Results to a Dashboard
Go has no reporter plugin, so reporting go test results means parsing go test -json and uploading the cases yourself. Here is the whole pattern.
How to Report Jest Test Results to a Dashboard
How to Report Jest Test Results to a Dashboard
How to send Jest results somewhere they are kept, viewable by the team, and comparable across runs, without giving up the default reporter
How to View Playwright Test Results in CI
How to View Playwright Test Results in CI
How to get Playwright results out of the CI console and into a durable dashboard, including parallel shards, screenshots, and retained history
What Is a Test Results Dashboard and When Do You Need One
What Is a Test Results Dashboard and When Do You Need One
What a test results dashboard actually does, how it differs from your CI logs and your test framework report, and the point at which a team starts needing one
Diagnosing CI Failures Automatically With an AI Failure Diagnosis API
Diagnosing CI Failures Automatically With an AI Failure Diagnosis API
How to turn a red build into a root cause, a regression list, and a deploy gate without a human reading the logs
How AI Coding Agents Use Test Results to Verify Their Own Work
How AI Coding Agents Use Test Results to Verify Their Own Work
Why a raw pass or fail is not enough for an agent to trust its own change, and how failure intelligence closes the self-verification loop
Store and View Pytest Results Over Time
Store and View Pytest Results Over Time
Why pytest results vanish after each CI run, and how to keep a durable history you can view, compare, and track over time
How to Group and Categorize Failing Tests by Root Cause
How to Group and Categorize Failing Tests by Root Cause
When a CI run shows dozens of failures, label each one with a root cause category and group them to see how many distinct problems you actually have
How to View JUnit XML Test Results in a Dashboard
How to View JUnit XML Test Results in a Dashboard
Upload JUnit XML to a dashboard in one step, and why a test framework library gives you richer reporting with logs, screenshots, and full history
How to Keep a History of Test Results Instead of Losing Them After Each CI Run
How to Keep a History of Test Results Instead of Losing Them After Each CI Run
Why CI logs and artifacts disappear, what you lose when they do, and how to retain a durable history of every test run
How to Query Test Results With AI Agents Using MCP
How to Query Test Results With AI Agents Using MCP
How to query your CI test data failures, flaky tests and regressions with AI agents using the Model Context Protocol
ROS 2 Test Reporting with Tesults
ROS 2 Test Reporting with Tesults
Native support for the full ROS 2 testing stack — C++, Python, Rust, and beyond