Skip to main content
Elastic UI
Elastic UI
ComponentsPatternsContentData visualization
EUI ChangelogGitHubFigma
  • Guidelines
    • Getting started
    • Accessibility
    • Writing
    • Testing
      • Recommendations
  • Theming
    • Theme provider
    • Color mode
    • High contrast mode
    • Borders
    • Breakpoints
    • Colors
    • Sizing
    • Typography
  • Templates
    • Page template
    • Sitewide search
  • Layout
    • Accordion
    • Bottom bar
    • Flex
    • Flyout
    • Header
    • Horizontal rule
    • Modal
    • Page components
    • Page header
    • Panel
    • Popover
    • Resizable container
    • Spacer
  • Navigation
    • Breadcrumbs
    • Buttons
    • Collapsible nav
    • Context menu
    • Facet
    • Key pad menu
    • Link
    • Pagination
    • Side nav
    • Steps
    • Tabs
    • Tree view
  • Display
    • Aspect ratio
    • Avatar
    • Badge
    • Callout
    • Card
    • Comment list
    • Description list
    • Drag and drop
    • Empty prompt
    • Health
    • Icons
    • Image
    • List group
    • Loading
    • Progress
    • Skeleton
    • Stat
    • Text
    • Timeline
    • Title
    • Toast
    • Tooltip
    • Tour
  • Forms
    • Form controls
    • Form layouts
    • Form validation
    • Text controls
    • Numeric controls
    • Selection controls
    • Search and filter controls
    • Date and time controls
    • Other controls
  • Tabular content
    • Tables
    • Data grid
  • Editors & Syntax
    • Code
    • Markdown
  • Utilities
    • Accessibility
    • Auto sizer
    • Beacon
    • Color palettes
    • Copy
    • CSS utility classes
    • Delay
    • Error boundary
    • Focus trap
    • Highlight and mark
    • HTML ID generator
    • I18n
    • Inner text
    • Mutation observer
    • Outside click detector
    • Overlay mask
    • Portal
    • Pretty duration
    • Provider
    • Resize observer
    • Scroll
    • Text diff
    • Text truncation
    • Window events
  • EUI
  • Guidelines
  • Testing
  • Recommendations

Testing recommendations


Our general set of do's and don'ts for testing components and views.

Choose the right selectors

Follow RTL's Guiding Principles and query priorities when choosing the right element selectors.

Prioritize accessible and semantic queries (e.g.,

[role="dialog"]) followed by data-test-subj attributes over other, more complicated and prone to breaking queries (e.g. div > span.title) whenever possible.

Check out our component-specific testing docs to find the selectors we officially support.

โœ„๐˜—
tsx code block:
โœ„๐˜—screen.getByRole('dialog'); // react-testing-library cy.get('[role="dialog"]'); // cypress driver.findElement(By.cssSelector('[role="dialog"]')); // selenium

Do:ย Use accessible and semantic queries.

โœ„๐˜—
tsx code block:
โœ„๐˜—container.querySelector('.euiFlyout'); // react-testing-library cy.get('.euiFlyout'); // cypress driver.findElement(By.cssSelector('.euiFlyout')); // selenium

Don't:ย Query by internal EUI selectors, especially when better selectors are available.

Don't use snapshots

The EUI team strongly discourages snapshot testing, despite its simplicity. Snapshot tests are prone to frequent failures due to the smallest things, like whitespace changes. Developers often update stored snapshots when they see them fail without thinking too much about why they fail.

Tests should tell a story and be considered an instant red flag whenever they fail. They should focus on the important details like the data a component is displaying or if the data is coming from a prop or being dynamically calculated.

Instead, consider writing simple but precise assertion tests.

โœ„๐˜—
tsx code block:
โœ„๐˜—const { getByText, getByRole } = render(<MyComponent />); expect(getByText('Hello, World!')).toBeInTheDocument(); expect(getByRole('button')).toHaveTextContent('Save');

Do:ย Query and assert on elements you actually want to test

โœ„๐˜—
tsx code block:
โœ„๐˜—const { container } = render(<MyComponent />); // react-testing-library expect(container).toMatchSnapshot();

Don't:ย Snapshot whole components

Avoid time-based waits

Sometimes the easiest solution to fixing a test is adding a wait/sleep call. In most cases, though, this can't be considered a reliable fix, because:

  1. It significantly increases total test run time, especially when used often
  2. Every machine will take a different amount of time to execute the code, and some โ€” especially CI runners โ€” are prone to lag during the test run.

Instead, use the utilities available for every testing framework to wait for elements to appear or for asynchronous operations to finish execution.

โœ„๐˜—
tsx code block:
โœ„๐˜—screen.getByRole('button', { name: 'Save document' }); expect(await screen.findByText('Document saved successfully')).toBeInTheDocument();

Do:ย Programmatically await changes to occur

โœ„๐˜—
tsx code block:
โœ„๐˜—screen.getByRole('button', { name: 'Save document' }); await new Promise((resolve) => setTimeout(resolve, 1000)); expect(screen.getByText('Document saved successfully')).toBeInTheDocument();

Don't:ย Add timeouts and other static waits

Write clear test names

Test cases and suites should have unambiguous names and match the naming convention throughout the project. Use short but descriptive names written in plain English.

We recommend using the third-person singular simple present tense for its short form and ease of reading.

โœ„๐˜—
tsx code block:
โœ„๐˜—describe('arraySearch()', () => { // use tested function name as the root group name it('accepts object arrays', () => { /* [...] */ }); it('accepts string arrays', () => { /* [...] */ }); it('throw on non-array inputs', () => { /* [...] */}); it('supports the `options.caseSensitive` option', () => { /*[...]*/ }); });

Do:ย Use clear and consistent names and test grouping

โœ„๐˜—
tsx code block:
โœ„๐˜—describe('array search', () => { // bad: not pointing to what exactly this group is testing it('object arrays', () => { /* [...] */ }); // bad: not enough context it('arraySearch(["a", "b"])', () => { /* [...] */ }); // bad: function call example may not be easily understandable it('should throw on non-array inputs', () => { /* [...] */ }); it('supports options.caseSensitive', () => { /* [...] */ }); // bad: using two different naming conventions; see line above });

Don't:ย Use inconsistent or unclear naming

Wrap property names and data in `

When including property and argument names in the test name string, wrap them in backticks (`) to clearly separate them from the rest of the text.

โœ„๐˜—
tsx code block:
โœ„๐˜—it('returns an empty object when the `value` string is empty');

Do:ย Wrap property names in backticks

โœ„๐˜—
tsx code block:
โœ„๐˜—it('returns an empty object when the value string is empty');

Don't:ย Have no separation between property names and the rest of the text

Add debug-friendly comments or error messages

Consider adding custom error messages or code comments for assertions that are not obvious. For jest, we recommend adding a comment on top or to the right of the assertion, so in case of an error, it will be printed out together as the failing code fragment.

โœ„๐˜—
tsx code block:
โœ„๐˜—// Total should equal the result of 1234^2 / 3.14 rounded to two decimal places expect(screen.getByText('Total: 484954.14')).toBeInTheDocument();

Do:ย Explain the source of the asserted value in code

Edit this page

Previous
Testing
Next
Theme provider
  • Choose the right selectors
  • Don't use snapshots
  • Avoid time-based waits
  • Write clear test names
    • Wrap property names and data in `
  • Add debug-friendly comments or error messages
EUI is dual-licensed under Elastic License 2.0 and Server Side Public License, v 1 | Crafted with โค by Elastic