Implementing Unit Testing in JavaScript with Jest

Guidelines on setting up and writing unit tests using Jest to ensure code reliability and maintainability in JavaScript projects.

0 likes
14 views

Rule Content

{
  "title": "Implementing Unit Testing in JavaScript with Jest",
  "description": "Guidelines on setting up and writing unit tests using Jest to ensure code reliability and maintainability in JavaScript projects.",
  "category": "JavaScript Cursor Rules",
  "rules": [
    {
      "name": "Use Descriptive Test Names",
      "description": "Ensure each test name clearly describes the functionality being tested and the expected outcome.",
      "examples": [
        {
          "bad": "test('works correctly', () => { /* test implementation */ });",
          "good": "test('should return the sum of two numbers', () => { /* test implementation */ });"
        }
      ]
    },
    {
      "name": "Follow the Arrange-Act-Assert Pattern",
      "description": "Structure tests into three distinct sections: setup (Arrange), execution (Act), and verification (Assert).",
      "examples": [
        {
          "bad": "test('should add numbers', () => { const result = add(1, 2); expect(result).toBe(3); });",
          "good": "test('should add numbers', () => { // Arrange const num1 = 1; const num2 = 2; // Act const result = add(num1, num2); // Assert expect(result).toBe(3); });"
        }
      ]
    },
    {
      "name": "Keep Tests Isolated and Independent",
      "description": "Ensure each test is self-contained and does not depend on the state or results of other tests.",
      "examples": [
        {
          "bad": "test('should increment counter', () => { counter.increment(); expect(counter.value).toBe(1); }); test('should decrement counter', () => { expect(counter.value).toBe(0); counter.decrement(); expect(counter.value).toBe(-1); });",
          "good": "test('should increment counter', () => { const counter = new Counter(); counter.increment(); expect(counter.value).toBe(1); }); test('should decrement counter', () => { const counter = new Counter(); counter.decrement(); expect(counter.value).toBe(-1); });"
        }
      ]
    },
    {
      "name": "Use Mocks and Spies Appropriately",
      "description": "Mock external dependencies and use spies to verify interactions, ensuring tests focus on the unit under test.",
      "examples": [
        {
          "bad": "test('should fetch user data', () => { const data = fetchData(); expect(data).toEqual({ id: 1, name: 'John Doe' }); });",
          "good": "test('should fetch user data', async () => { const mockFetch = jest.fn().mockResolvedValue({ id: 1, name: 'John Doe' }); const data = await fetchData(mockFetch); expect(mockFetch).toHaveBeenCalled(); expect(data).toEqual({ id: 1, name: 'John Doe' }); });"
        }
      ]
    },
    {
      "name": "Avoid Testing Implementation Details",
      "description": "Focus on testing the output and behavior of functions rather than their internal implementation.",
      "examples": [
        {
          "bad": "test('should call helper function', () => { const spy = jest.spyOn(module, 'helperFunction'); mainFunction(); expect(spy).toHaveBeenCalled(); });",
          "good": "test('should return correct result', () => { const result = mainFunction(); expect(result).toBe('expected result'); });"
        }
      ]
    },
    {
      "name": "Utilize Setup and Teardown Methods",
      "description": "Use Jest's lifecycle methods to set up and clean up resources before and after tests to maintain a consistent test environment.",
      "examples": [
        {
          "bad": "test('should process data', () => { const db = new Database(); db.connect(); const result = processData(db); expect(result).toBe('processed data'); db.disconnect(); });",
          "good": "describe('Data Processing', () => { let db; beforeAll(() => { db = new Database(); db.connect(); }); afterAll(() => { db.disconnect(); }); test('should process data', () => { const result = processData(db); expect(result).toBe('processed data'); }); });"
        }
      ]
    },
    {
      "name": "Ensure Tests Are Deterministic",
      "description": "Write tests that produce the same results every time they are run, regardless of external factors.",
      "examples": [
        {
          "bad": "test('should return current date', () => { const result = getCurrentDate(); expect(result).toBe(new Date().toISOString()); });",
          "good": "test('should return current date', () => { const mockDate = new Date('2025-06-03T00:00:00Z'); jest.useFakeTimers().setSystemTime(mockDate); const result = getCurrentDate(); expect(result).toBe('2025-06-03'); jest.useRealTimers(); });"
        }
      ]
    },
    {
      "name": "Maintain High Test Coverage",
      "description": "Aim for comprehensive test coverage to ensure all code paths are tested, enhancing code reliability.",
      "examples": [
        {
          "bad": "test('should add numbers', () => { const result = add(1, 2); expect(result).toBe(3); }); // No tests for subtract function",
          "good": "test('should add numbers', () => { const result = add(1, 2); expect(result).toBe(3); }); test('should subtract numbers', () => { const result = subtract(2, 1); expect(result).toBe(1); });"
        }
      ]
    },
    {
      "name": "Use Snapshot Testing for UI Components",
      "description": "Employ snapshot testing to capture the rendered output of UI components and detect unintended changes.",
      "examples": [
        {
          "bad": "test('should render component', () => { const component = render(<MyComponent />); expect(component).toBeDefined(); });",
          "good": "test('should match snapshot', () => { const component = render(<MyComponent />); expect(component).toMatchSnapshot(); });"
        }
      ]
    },
    {
      "name": "Run Tests in Continuous Integration",
      "description": "Integrate tests into the CI/CD pipeline to automatically run them on code changes, ensuring ongoing code quality.",
      "examples": [
        {
          "bad": "// No CI integration for tests",
          "good": "// .github/workflows/ci.yml name: CI on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install dependencies run: npm install - name: Run tests run: npm test"
        }
      ]
    }
  ]
}