Skip to main content

Testing

This guide covers testing practices for both frontend and backend code in Grafana.

Frontend testing

  • Default to *ByRole queries - They encourage testing with accessibility in mind
  • Alternative: *ByLabelText queries - Though *ByRole queries are more robust
  • Use React Testing Library - Don’t create new snapshot tests; we’re removing existing ones
  • Migrate Enzyme tests - When modifying existing tests, migrate from Enzyme to RTL (unless fixing a bug)

Testing user interactions

Use the user-event library instead of fireEvent:
  • All userEvent methods are asynchronous - use await
  • Call userEvent.setup() before tests (use the utility function pattern above)

Debugging tests

Useful utilities:
  • screen.debug() - Prints DOM tree to console
  • Testing Playground - Interactive sandbox for testing queries
  • prettyDOM logRoles - Prints implicit ARIA roles for a DOM tree

Testing Select components

Query by label

Add a label element with htmlFor matching the inputId, or use aria-label:

Test displayed options

Click the Select and match options using *ByText:

Select an option

Use the selectOptionInTest utility (wraps react-select-event):

Mocking

Mock window object

Use Jest spies (they auto-restore):

Mock getBackendSrv()

For HTTP requests to Grafana backend:

Mock getBackendSrv for AsyncSelect

Running frontend tests

Backend testing

Test framework

Use the standard library testing package. For assertions, prefer testify.

TestMain and test suite

Each package SHOULD include a TestMain function that calls testsuite.Run(m):
For tests that use the database, you MUST define TestMain so test databases can be cleaned up properly.
Only define TestMain once per package (in one _test.go file).

Integration tests

Mark integration tests properly to keep CI running smoothly:
If you don’t follow this convention, your integration test may run twice or not at all.

Assertions

  • Use assert.* for “soft checks” (don’t halt test)
  • Use require.* for “hard checks” (halt test on failure)
Typically use require.* for error assertions, since continuing after an error is chaotic and often causes segfaults.

Sub-tests

Use t.Run to group test cases:
This allows:
  • Common setup/teardown code
  • Running test cases in isolation when debugging
Don’t use t.Run just to group assertions.

Cleanup

Use t.Cleanup instead of defer (it works in helper functions):
Cleanup functions execute in reverse order after the test completes.

Mocking with testify/mock

Basic mock implementation

Given this interface:
Mock it like this:

Using mocks in tests

Tips:
  • Use Once() or Times(n) to limit call count
  • Use mockedClass.AssertExpectations(t) to verify call counts
  • Use mock.Anything when you don’t care about the argument
  • Use mockedClass.AssertNotCalled(t, "MethodName") to assert a method wasn’t called

Generate mocks with mockery

For large interfaces, use mockery to generate mocks:
Or add a go:generate comment:

Running backend tests

Test requirements for pull requests

  • Include tests that verify the intended behavior
  • For bug fixes, include tests that replicate the bug (prevent regressions)
  • Run appropriate tests as part of your PR
  • Ensure all CI checks pass before merge