Testing
This guide covers testing practices for both frontend and backend code in Grafana.
Frontend testing
Recommended practices
- 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