jest
jesttestingjavascripttypescriptbest-practices
Description
This rule provides guidelines for writing clean, maintainable, and effective tests using Jest. It covers code organization, performance, common pitfalls, and best practices for testing JavaScript and TypeScript projects.
Globs
**/*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}
---
description: This rule provides guidelines for writing clean, maintainable, and effective tests using Jest. It covers code organization, performance, common pitfalls, and best practices for testing JavaScript and TypeScript projects.
globs: **/*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}
---
- **Organize tests by feature or module:**
- Group tests into files or directories that correspond to the features or modules they are testing. This makes it easier to locate and maintain tests.
- Create a `__tests__` directory alongside your source code files. This is a common convention that Jest recognizes.
- **Use descriptive test names:**
- Write test names that clearly describe what the test is verifying. This makes it easier to understand the purpose of each test and to diagnose failures.
- Use the `describe` and `it` blocks to structure your tests and provide context.
- Example: `describe('User authentication', () => { it('should log in a user with valid credentials', () => { /* ... */ }); });`
- **Keep tests isolated and independent:**
- Each test should be independent of other tests. Avoid sharing state or dependencies between tests.
- Use `beforeEach` and `afterEach` hooks to set up and tear down the environment for each test.
- **Avoid testing implementation details:**
- Focus on testing the public API of your code, rather than the internal implementation details.
- This makes your tests more resilient to changes in the implementation.
- Test the "what", not the "how".
- **Use setup and teardown methods:**
- Use `beforeAll`, `afterAll`, `beforeEach`, and `afterEach` hooks to set up and tear down the environment for your tests.
- `beforeAll` and `afterAll` run once before and after all tests in a `describe` block.
- `beforeEach` and `afterEach` run before and after each test in a `describe` block.
- **Mock external dependencies:**
- Use mocking to isolate your code from external dependencies, such as network requests or database connections.
- Jest provides built-in mocking capabilities with `jest.mock` and `jest.spyOn`.
- Consider using a library like `axios-mock-adapter` for mocking HTTP requests.
- **Write tests that are easy to read and maintain:**
- Keep your tests concise and focused.
- Use clear and consistent formatting.
- Add comments to explain complex logic.
- Refactor your tests regularly to keep them up to date.
- **Aim for high test coverage, but prioritize meaningful tests over quantity:**
- Aim for high test coverage to ensure that your code is well-tested.
- However, prioritize writing meaningful tests that verify the core functionality of your code.
- Don't just aim for 100% coverage without considering the value of each test.
- **Use Jest's built-in matchers effectively:**
- Jest provides a rich set of matchers for asserting different conditions.
- Use matchers like `toBe`, `toEqual`, `toBeGreaterThan`, `toContain`, `toHaveBeenCalled`, etc.
- Explore the Jest documentation for the full list of matchers.
- **Handle asynchronous code correctly:**
- Use `async/await` or Promises to handle asynchronous code in your tests.
- Use the `resolves` and `rejects` matchers to assert that a Promise resolves or rejects.
- Example: `expect(myAsyncFunction()).resolves.toBe(expectedValue);`
- **Test error handling:**
- Write tests to verify that your code handles errors correctly.
- Use the `toThrow` matcher to assert that a function throws an error.
- Example: `expect(() => myDangerousFunction()).toThrow(Error);`
- **Use snapshots sparingly:**
- Snapshots can be useful for verifying the output of a component or function.
- However, they can also be brittle and difficult to maintain if used excessively.
- Use snapshots strategically and review them carefully when they change.
- **Configure Jest correctly:**
- Configure Jest using the `jest.config.js` or `jest.config.ts` file.
- Configure settings such as test environment, module file extensions, and coverage thresholds.
- Consider using presets like `ts-jest` or `babel-jest` for TypeScript or Babel support.
- **Leverage code coverage reports:**
- Use Jest's code coverage reports to identify areas of your code that are not well-tested.
- Aim to increase coverage in critical areas of your codebase.
- Use the `--coverage` flag to generate coverage reports.
- **Keep test data separate from test logic:**
- Externalize test data to improve readability and maintainability.
- Use fixtures or factories to generate test data.
- Avoid hardcoding data directly in your tests.
- **Consider using test-driven development (TDD):**
- Write tests before you write code to drive the development process.
- This can help you write more testable and well-designed code.
- **Run tests frequently:**
- Run your tests frequently to catch errors early.
- Use Jest's watch mode to automatically run tests when files change.
- Integrate tests into your CI/CD pipeline.
- **Document your tests:**
- Add comments to explain the purpose of each test and the expected behavior.
- This will make it easier for others to understand and maintain your tests.
- **Code Organization and Structure:**
- **Directory structure best practices:** Organize test files alongside the component/module they test (e.g., `src/components/MyComponent/MyComponent.test.js`)
- **File naming conventions:** Use `.test.js` or `.spec.js` suffixes for test files (e.g., `MyComponent.test.js`, `MyModule.spec.ts`).
- **Module organization:** Keep test files close to the modules they are testing. Use a consistent naming convention for test files.
- **Component architecture:** Test components in isolation, mocking dependencies where necessary.
- **Code splitting strategies:** Ensure tests cover all code paths in dynamically imported modules.
- **Common Patterns and Anti-patterns:**
- **Design patterns specific to Jest:** Use Page Object Model (POM) for UI tests, Factory pattern for test data generation.
- **Recommended approaches for common tasks:** Use `jest.mock` for mocking modules, `jest.spyOn` for spying on methods, and `fakeTimers` for controlling time-dependent behavior.
- **Anti-patterns and code smells to avoid:** Avoid testing implementation details, relying on global state, and creating brittle snapshots.
- **State management best practices:** Mock external state dependencies and verify state changes using `expect` assertions.
- **Error handling patterns:** Test for specific error messages and ensure error boundaries are properly tested.
- **Performance Considerations:**
- **Optimization techniques:** Use `jest.clearAllMocks` and `jest.resetAllMocks` in `beforeEach` blocks to prevent state leakage and improve test performance.
- **Memory management:** Avoid creating large data structures in tests that are not necessary. Manually trigger garbage collection in tests where large objects are created and released.
- **Rendering optimization:** Mock expensive rendering logic to speed up tests that involve React components.
- **Bundle size optimization:** Not applicable, as Jest primarily tests individual modules or components.
- **Lazy loading strategies:** Ensure tests cover all code paths in dynamically imported modules.
- **Security Best Practices:**
- **Common vulnerabilities and how to prevent them:** Avoid using sensitive data in test snapshots. Sanitize test data to prevent potential injection attacks.
- **Input validation:** Test input validation logic and ensure that invalid inputs are handled correctly.
- **Authentication and authorization patterns:** Mock authentication and authorization logic to test different user roles and permissions.
- **Data protection strategies:** Not directly applicable, as Jest primarily focuses on functional testing.
- **Secure API communication:** Mock API calls and verify that data is transmitted securely.
- **Testing Approaches:**
- **Unit testing strategies:** Test individual functions, classes, or components in isolation.
- **Integration testing:** Test interactions between different modules or components.
- **End-to-end testing:** Use tools like Cypress or Playwright for end-to-end tests.
- **Test organization:** Group tests into logical suites based on functionality or module.
- **Mocking and stubbing:** Use `jest.mock` and `jest.spyOn` to create mocks and stubs for dependencies.
- **Common Pitfalls and Gotchas:**
- **Frequent mistakes developers make:** Forgetting to mock dependencies, testing implementation details, and creating brittle snapshots.
- **Edge cases to be aware of:** Testing asynchronous code correctly, handling errors, and testing different input types.
- **Version-specific issues:** Be aware of breaking changes in Jest updates and update your tests accordingly.
- **Compatibility concerns:** Ensure tests are compatible with different browsers or environments.
- **Debugging strategies:** Use `console.log` statements, debuggers, or Jest's interactive mode to debug tests.
- **Tooling and Environment:**
- **Recommended development tools:** VS Code, WebStorm, Jest Runner extension.
- **Build configuration:** Configure Jest using `jest.config.js` or `package.json`.
- **Linting and formatting:** Use ESLint and Prettier to enforce code style and prevent errors.
- **Deployment best practices:** Integrate tests into your CI/CD pipeline to ensure code quality.
- **CI/CD integration:** Use tools like GitHub Actions, Jenkins, or CircleCI to automate testing and deployment.