Hone logo
Hone
Problems

Jest Snapshot Testing: Verifying UI Component Stability

Snapshot testing is a powerful technique in Jest for verifying that a UI component's output has not changed unexpectedly. This challenge will guide you through implementing snapshot tests for a simple React component, ensuring its visual representation remains consistent over time.

Problem Description

Your task is to create Jest snapshot tests for a given React component. Snapshot tests work by taking a "snapshot" of the rendered output of a component and then comparing it against a previously saved snapshot. If the component's output changes, the test will fail, alerting you to potential regressions or unintended modifications.

Key Requirements:

  1. Component Rendering: You'll be provided with a basic React functional component.
  2. Jest Setup: Ensure you have Jest and ts-jest configured for a TypeScript project.
  3. Snapshot Creation: Write a test that renders the component and creates an initial snapshot.
  4. Snapshot Assertion: Use Jest's toMatchSnapshot() matcher to assert that the rendered output matches the saved snapshot.
  5. Handling Updates: Understand how to update snapshots when intended changes are made to the component.

Expected Behavior:

  • The first time the test runs, a snapshot file (.snap) will be generated.
  • Subsequent runs will compare the current rendered output against this snapshot.
  • If the rendered output differs from the snapshot, the test will fail.
  • You will be able to update the snapshot if the changes are intentional.

Examples

Let's consider a simple Button component.

Example 1: Basic Button

Input:

// src/components/Button.tsx
import React from 'react';

interface ButtonProps {
  label: string;
  onClick: () => void;
  disabled?: boolean;
}

const Button: React.FC<ButtonProps> = ({ label, onClick, disabled = false }) => {
  return (
    <button onClick={onClick} disabled={disabled} className="btn">
      {label}
    </button>
  );
};

export default Button;

Test (initially):

// src/components/Button.test.ts
import React from 'react';
import { render } from '@testing-library/react';
import Button from './Button';

describe('Button', () => {
  it('should render correctly and match snapshot', () => {
    const mockOnClick = jest.fn();
    const { container } = render(<Button label="Click Me" onClick={mockOnClick} />);
    expect(container).toMatchSnapshot();
  });
});

Output (after first run): A file named Button.test.ts.snap will be generated containing something like:

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Button should render correctly and match snapshot 1`] = `
<button class="btn">
  Click Me
</button>
`;

Example 2: Disabled Button

Input:

// src/components/Button.tsx (same as above)

Test:

// src/components/Button.test.ts
import React from 'react';
import { render } from '@testing-library/react';
import Button from './Button';

describe('Button', () => {
  it('should render a disabled button and match snapshot', () => {
    const mockOnClick = jest.fn();
    const { container } = render(<Button label="Disabled" onClick={mockOnClick} disabled />);
    expect(container).toMatchSnapshot();
  });
});

Output (after first run for this test): A new snapshot entry will be added to Button.test.ts.snap:

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Button should render a disabled button and match snapshot 1`] = `
<button class="btn" disabled="">
  Disabled
</button>
`;

Example 3: Button with different label

Input:

// src/components/Button.tsx (same as above)

Test:

// src/components/Button.test.ts
import React from 'react';
import { render } from '@testing-library/react';
import Button from './Button';

describe('Button', () => {
  it('should render with a different label and match snapshot', () => {
    const mockOnClick = jest.fn();
    const { container } = render(<Button label="Submit" onClick={mockOnClick} />);
    expect(container).toMatchSnapshot();
  });
});

Output (after first run for this test): Another snapshot entry in Button.test.ts.snap:

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Button should render with a different label and match snapshot 1`] = `
<button class="btn">
  Submit
</button>
`;

If you were to change the Button component's implementation (e.g., add an id attribute) and rerun the tests without updating snapshots, the tests for all rendered snapshots would fail.

Constraints

  • Your solution should be written in TypeScript.
  • You are expected to use @testing-library/react for rendering React components in your tests.
  • The provided component and tests should be runnable within a standard Jest testing environment for a React/TypeScript project.

Notes

  • You will need to have jest, @types/jest, react, react-dom, @testing-library/react, and ts-jest installed and configured in your project.
  • The toMatchSnapshot() matcher automatically handles the creation and comparison of snapshots.
  • When a snapshot test fails, review the diff to understand the changes. If the changes are intentional, run Jest with the -u flag (e.g., npm test -- -u or yarn test -u) to update the snapshot file.
  • Consider how passing different props to the component will affect the snapshot.
  • The generated snapshot files should be placed alongside their corresponding test files.
Loading editor...
typescript