Unit Testing Guidelines
Best practices for writing and reviewing unit tests. Contains rules covering test structure, naming, determinism, and code review.
Reference: MetaMask Unit Testing Guidelines
When to Apply
Reference these guidelines when:
- Writing new unit tests
- Reviewing test code in PRs
- Refactoring existing tests
- Debugging flaky or brittle tests
- Improving test coverage
Rule Categories by Priority
| Priority | Category | Impact | Rule File |
| -------- | --------------- | -------- | ---------------------------- |
| 1 | Best Practices | CRITICAL | rules/best-practices.md |
| 2 | Determinism | HIGH | rules/determinism.md |
| 3 | Reviewer Guide | MEDIUM | rules/reviewer-guide.md |
| 4 | Anti-patterns | MEDIUM | rules/anti-patterns.md |
Quick Reference
1. Best Practices (CRITICAL)
Use the AAA pattern (Arrange, Act, Assert):
it('indicates expired milk when past due date', () => {
// Arrange
const today = new Date('2025-06-01');
const milk = { expiration: new Date('2025-05-30') };
// Act
const result = isMilkGood(today, milk);
// Assert
expect(result).toBe(false);
});
Meaningful test names - describe purpose, not implementation:
it('displays an error when input is invalid', () => { ... });
One behavior per test, isolated from others.
See rules/best-practices.md for complete guidance.
2. Determinism (HIGH)
Mock time, randomness, and external systems:
jest.useFakeTimers();
jest.setSystemTime(new Date('2024-01-01'));
- Avoid relying on global state or hardcoded values
- Only test public behavior, not implementation details
See rules/determinism.md for details.
3. Reviewer Guide (MEDIUM)
Test the test - validate tests fail when code is broken:
// Break the SuT and make sure this test fails
expect(result).toBe(false);
- Ensure proper matchers (
toBeOnTheScreenvstoBeDefined) - Reject complex test names with multiple conditions
See rules/reviewer-guide.md for details.
4. Anti-patterns (MEDIUM)
Avoid:
- Code coverage without real assertions
- Weak matchers (
toBeDefined,toBeTruthy) for element presence
See rules/anti-patterns.md for examples.
Test Scope and Verification
Do not write tests for reversible, low-impact changes that mirror the implementation. If you do choose to verify your work with tests, make sure that the tests are meaningful and necessary to verify implementation.
Run tests appropriate to the change and complete required checks. Once those pass, broaden or repeat testing only when new changes, failures, or unresolved concerns justify it; otherwise, continue toward completing the task.
PR Checklist
Before submitting a PR with tests:
- [ ] Tests use AAA pattern (Arrange, Act, Assert)
- [ ] Test names describe the expected behavior
- [ ] One behavior per test
- [ ] No reliance on global state or implementation details
- [ ] Time/randomness mocked where needed
- [ ] Proper matchers used for assertions
- [ ] Checked for existing
*TestUtils/*TestFactoryclasses before creating new fixtures - [ ] Extracted shared fixtures to utility class if same setup needed in 2+ test files
- [ ] All tests pass locally