Hone logo
Hone
Problems

Building a Visual Regression System in React

This challenge asks you to build a core component of a visual regression testing system. Visual regression testing is crucial for ensuring that UI changes don't introduce unintended visual bugs. You will create a React component that compares two snapshots of a UI element and highlights any differences.

Problem Description

Your task is to develop a React component named VisualDiff that accepts two snapshots of a UI element and visually indicates the differences between them. The component should render the "baseline" snapshot and the "current" snapshot side-by-side, or overlaid, and clearly highlight the areas that have changed.

Key Requirements:

  1. Component Structure: Create a functional React component VisualDiff that accepts two React.ReactNode props: baseline and current.
  2. Rendering: The component should render both baseline and current snapshots.
  3. Difference Highlighting: Visually identify and highlight the differences between baseline and current. This could be achieved through various methods, such as:
    • Overlaying the current snapshot on top of the baseline and highlighting differing pixels.
    • Displaying them side-by-side with bounding boxes around differing regions.
    • A combination of both.
  4. Difference Threshold: Implement a mechanism to ignore minor, insignificant differences (e.g., single pixel shifts, anti-aliasing differences) to reduce false positives. A configurable threshold prop (e.g., a number between 0 and 1 representing the percentage of pixels that must differ) would be beneficial.
  5. Styling: The component should be styled to clearly present the comparison and highlights.
  6. Responsiveness (Optional but Recommended): Consider how the component will behave on different screen sizes.

Expected Behavior:

  • When baseline and current are identical, no highlighting should be present.
  • When there are differences, those differences should be prominently and clearly marked.
  • The threshold prop should effectively control the sensitivity of difference detection.

Edge Cases to Consider:

  • Empty Snapshots: What happens if baseline or current is null or undefined?
  • Different Dimensions: How does the component handle snapshots with different dimensions (width/height)?
  • Complex DOM Structures: How does the component effectively compare deeply nested or complex React elements?

Examples

Example 1: Simple Text Difference

Input:
baseline: <div>Hello World</div>
current: <div>Hello React</div>

Output:
[VisualDiff component rendering]
Side-by-side or overlaid views of "Hello World" and "Hello React", with the word "World" vs. "React" highlighted as a difference.

Explanation: The text content has changed, and the component correctly identifies and highlights this change.

Example 2: Styling Change

Input:
baseline: <div style={{ color: 'blue', fontSize: '16px' }}>Styled Text</div>
current: <div style={{ color: 'red', fontSize: '18px' }}>Styled Text</div>

Output:
[VisualDiff component rendering]
The text "Styled Text" will be rendered, and the color and font size differences will be highlighted (e.g., the bounding box around the text might indicate these style changes).

Explanation: Although the text content is the same, the styling has changed, which the visual regression system should detect.

Example 3: No Difference

Input:
baseline: <button>Click Me</button>
current: <button>Click Me</button>

Output:
[VisualDiff component rendering]
A rendered button with "Click Me" text, with no highlighting indicating differences.

Explanation: The two snapshots are identical.

Constraints

  • The solution must be implemented in TypeScript and React.
  • The component should aim for reasonable performance, especially when comparing large or complex UI trees. Avoid computationally expensive operations on every render if possible.
  • The threshold prop, if implemented, should be a number between 0 (most sensitive) and 1 (least sensitive). A value of 0 means even a single pixel difference will be flagged. A value of 1 means only a complete visual match will pass.
  • Assume that the provided React.ReactNode can be rendered to an HTML element or a canvas for comparison.

Notes

  • For actual visual regression, you'd typically capture screenshots of rendered components and compare image data. For this challenge, we'll abstract the comparison logic. You can simulate the comparison by assuming a function compareNodes(nodeA: React.ReactNode, nodeB: React.ReactNode, threshold: number): DifferenceData exists, which returns information about differences. Your VisualDiff component will then render these differences based on the DifferenceData.
  • Consider using a library like pixelmatch (if you were to implement actual pixel comparison) as inspiration for how differences are represented and highlighted. For this challenge, you can focus on the React component structure and how it visualizes pre-computed differences.
  • The core challenge lies in how you structure your React component to accept snapshots and visually represent the differences. Think about how you would represent the DifferenceData if you were to implement the comparison logic.
  • You might need to render the React nodes into a DOM or canvas element to facilitate comparison. This might involve using ReactDOM.render or similar techniques within your component or a helper.
Loading editor...
typescript