Understanding Jest Queries: The Interplay Between the DOM and Accessibility Trees

Basavaraj PatilBasavaraj Patil
4 min read

Hello everyone! As a frontend React developer with four years of experience, I’ve recently been diving deep into the world of accessibility (A11Y). While working on making our applications more inclusive, I stumbled upon a fascinating concept: the accessibility tree. This exploration led me to understand how our testing library, Jest, interacts with both the real DOM and the accessibility tree.

While implementing accessibility features, I often used attributes like aria-hidden="true" to hide certain content from assistive technologies, such as screen readers. However, I encountered unexpected test failures when I tried to access these elements using the getByRole query. Intrigued, I began to debug and understand why these issues arose. In this blog, I’d like to share some insights about Jest queries and their interactions with the DOM and accessibility tree.

Why Do We Have Different Queries?

Jest, in conjunction with Testing Library, provides various query methods to access elements in your components. The most common ones are:

  • getByRole: Targets elements based on their role in the accessibility tree, making it essential for accessibility testing.

  • getByText: Locates elements by their visible text content in the DOM, which is useful for asserting the presence of specific text.

Example:

import { render, screen } from '@testing-library/react';

// A simple component for demonstration
const TestComponent = () => (
  <div>
    <img src="decorative-image.jpg" alt="" aria-hidden="true" />
    <img src="visible-image.jpg" alt="Visible Image" />
  </div>
);

test('renders images correctly', () => {
  render(<TestComponent />);

  // Attempt to find the decorative image by role
  const decorativeImage = screen.queryByRole('img', { hidden: true });
  expect(decorativeImage).not.toBeInTheDocument(); // Will fail due to aria-hidden

  // Successfully find the visible image using getByAltText
  const visibleImage = screen.getByAltText('Visible Image');
  expect(visibleImage).toBeInTheDocument();
});

How aria-hidden="true" Affects Testing

Using aria-hidden="true" means that elements will not be represented in the accessibility tree. Consequently, queries like getByRole will not return these elements, leading to test failures if you try to access them that way.

For example, when I tried to find a decorative image with aria-hidden="true" using getByRole, Jest couldn’t locate it since that image is excluded from the accessibility tree. However, I could still access the visible image using getByAltText, as it operates on the real DOM, which still contains the element.

Example of Test Case:

import { render, screen } from '@testing-library/react';

// Component with images
const ImageComponent = () => (
  <div>
    <img src="hidden-image.jpg" alt="" aria-hidden="true" />  {/* Decorative image */}
    <img src="visible-image.jpg" alt="Visible Image" />       {/* Visible image */}
  </div>
);

test('tests images accessibility', () => {
  render(<ImageComponent />);

  // This will not find the decorative image due to aria-hidden
  const hiddenImage = screen.queryByRole('img', { hidden: true });
  expect(hiddenImage).not.toBeInTheDocument(); // Fails as expected

  // Successfully find the visible image
  const visibleImage = screen.getByAltText('Visible Image');
  expect(visibleImage).toBeInTheDocument(); // Passes
});

When to Use Which Query

Understanding when to use these queries can make a significant difference in your testing strategy:

  • Use getByRole when:

    • You want to ensure your application is accessible.

    • You're testing user interactions with interactive elements.

  • Use getByText when:

    • You need to assert that specific text is displayed in the component.

    • The content isn't tied to any particular role.

Reading the Real DOM and Accessibility Tree

When debugging or writing tests, understanding the distinction between the real DOM and the accessibility tree is crucial:

  • The real DOM represents everything rendered in the browser. All elements, regardless of their visibility, are part of this tree. Queries like getByText can access any element that contains visible text.

  • The accessibility tree is a subset designed specifically for assistive technologies. Elements with aria-hidden="true" or those hidden via CSS are excluded from this tree, so queries like getByRole will not return them.

Conclusion

In conclusion, my journey into accessibility has opened my eyes to the complexities of testing in React applications. By understanding how Jest queries interact with both the real DOM and the accessibility tree, we can write more effective tests that verify functionality and ensure our applications are accessible to everyone.

Whether you're a seasoned developer or just starting, I encourage you to dive into the world of accessibility and testing. It’s a rewarding experience that ultimately benefits all users. What challenges have you faced in ensuring your applications are accessible? Share your experiences below!

0
Subscribe to my newsletter

Read articles from Basavaraj Patil directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Basavaraj Patil
Basavaraj Patil

I am working as a software developer for more than 1year now, I am interested in writing code and blogs.