;
};
});
Console Error Handling
~~~~~~~~~~~~~~~~~~~~~~
Suppress expected console errors in tests:
.. code-block:: javascript
it('should handle API errors gracefully', async () => {
HttpClient.get.mockRejectedValue(new Error('Network error'));
const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
renderComponent();
await waitFor(() => {
expect(consoleSpy).toHaveBeenCalled();
});
consoleSpy.mockRestore();
});
Best Practices
--------------
Testing Library Queries
~~~~~~~~~~~~~~~~~~~~~~~
Use accessible queries in this priority order:
1. ``getByRole`` - Most accessible, semantic
2. ``getByLabelText`` - Form elements
3. ``getByPlaceholderText`` - Input placeholders
4. ``getByText`` - Visible text content
5. ``getByTestId`` / ``getByOuiaId`` - PatternFly components
.. code-block:: javascript
// Preferred: accessible queries
screen.getByRole('button', { name: /submit/i });
screen.getByLabelText('Email');
// For PatternFly OUIA components
screen.getByTestId('filter-table-card');
Async Testing
~~~~~~~~~~~~~
Always use ``waitFor`` for async operations:
.. code-block:: javascript
// Good: Wait for async content
await waitFor(() => {
expect(screen.getByText('Loaded Content')).toBeInTheDocument();
});
// Good: Wait for API calls
await waitFor(() => {
expect(HttpClient.get).toHaveBeenCalled();
});
// Avoid: Using arbitrary delays
// await new Promise(resolve => setTimeout(resolve, 1000));
User Events
~~~~~~~~~~~
Use ``userEvent`` for realistic user interactions:
.. code-block:: javascript
import userEvent from '@testing-library/user-event';
it('should handle form submission', async () => {
const user = userEvent.setup();
renderComponent();
await user.type(screen.getByLabelText('Email'), 'test@example.com');
await user.type(screen.getByLabelText('Password'), 'password123');
await user.click(screen.getByRole('button', { name: /login/i }));
expect(HttpClient.post).toHaveBeenCalledWith(
expect.any(Array),
expect.objectContaining({ email: 'test@example.com' })
);
});
PatternFly Component Testing
----------------------------
Understanding OUIA (Open UI Automation)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PatternFly components implement OUIA attributes for automated testing. The frontend is configured to use ``data-ouia-component-id`` as the test ID attribute (see ``setupTests.js``).
.. code-block:: javascript
// setupTests.js configures this:
configure({ testIdAttribute: 'data-ouia-component-id' });
// This means getByTestId() looks for data-ouia-component-id
expect(screen.getByTestId('my-component')).toBeInTheDocument();
Components Supporting ``ouiaId`` Prop
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
These PatternFly components support the ``ouiaId`` prop, which automatically sets ``data-ouia-component-id``:
**Core Components:**
* Alert, Button, Card, Modal, Pagination, Toolbar
**Navigation:**
* Breadcrumb, Nav, NavItem, NavExpandable
**Form Controls:**
* Checkbox, Radio, Switch, TextInput, FormSelect
**Menus:**
* Dropdown, DropdownItem, Menu, MenuToggle, Select
**Content:**
* Content, Title, ClipboardCopy
**Tabs:**
* Tab, Tabs, TabContent
Components WITHOUT ``ouiaId`` Support
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
These components do **NOT** support the ``ouiaId`` prop. Use ``data-ouia-component-id`` directly only when necessary:
**Card Sub-components:**
* CardBody, CardHeader, CardFooter, CardTitle
**Modal Sub-components:**
* ModalBody, ModalHeader
**Toolbar Sub-components:**
* ToolbarItem, ToolbarGroup, ToolbarContent
**Layout Components:**
* Grid, GridItem, Flex, FlexItem, PageSection
Test Locator Strategy
~~~~~~~~~~~~~~~~~~~~~~
**Preferred: Use ``ouiaId`` on Parent Components**
.. code-block:: javascript
// Component
// Test - use relative locators from parent
const card = screen.getByTestId('test-card');
const button = within(card).getByRole('button', { name: /click me/i });
**Use ``data-ouia-component-id`` Only When Necessary**
.. code-block:: javascript
// Component - only when relative locators won't work
Complex content
// Test
expect(screen.getByTestId('special-card-body')).toBeInTheDocument();
PatternFly Component Examples
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Testing Modal with OUIA:**
.. code-block:: javascript
// Component
Edit Item
// Test
it('should render modal with input', () => {
renderComponent();
const modal = screen.getByTestId('edit-modal');
expect(modal).toBeInTheDocument();
const input = screen.getByTestId('item-name-input');
expect(input).toBeInTheDocument();
});
**Testing Card with OUIA:**
.. code-block:: javascript
// Component
Results: 100
// Test
it('should display results in card', () => {
renderComponent();
const card = screen.getByTestId('results-card');
expect(within(card).getByText(/results: 100/i)).toBeInTheDocument();
});
**Testing Button with OUIA:**
.. code-block:: javascript
// Component
// Test
it('should handle button click', async () => {
const user = userEvent.setup();
renderComponent();
const button = screen.getByTestId('submit-button');
await user.click(button);
expect(mockHandleSubmit).toHaveBeenCalled();
});
Checking Component Support for ``ouiaId``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To verify if a PatternFly component supports ``ouiaId``:
1. Check the component's TypeScript interface in ``node_modules/@patternfly/react-core/src/components/``
2. Look for ``extends OUIAProps`` in the interface definition
3. Refer to the list in ``AGENTS.md`` for quick reference
.. code-block:: typescript
// Example: Card supports ouiaId
export interface CardProps extends React.HTMLProps, OUIAProps {
ouiaId?: number | string;
// ...
}
// Example: CardBody does NOT support ouiaId
export interface CardBodyProps extends React.HTMLProps {
// No OUIAProps extension
// ...
}
Mocking PatternFly Components in Tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When mocking PatternFly components, include ``data-ouia-component-id`` for test compatibility:
.. code-block:: javascript
jest.mock('../components/my-component', () => {
return function MyComponent({ title, ouiaId }) {
return (
{title}
);
};
});
Common Pitfalls
~~~~~~~~~~~~~~~
**Don't use ``ouiaId`` on unsupported components:**
.. code-block:: javascript
// Bad: CardBody doesn't support ouiaId
Content
// Good: Use data-ouia-component-id if needed
Content
// Better: Use relative locator from parent Card
Content
**Don't use ``data-id`` for test selectors:**
The ``data-id`` attribute is obsolete for testing. Use ``data-ouia-component-id`` or ``ouiaId`` prop instead.
.. code-block:: javascript
// Bad: Legacy data-id (pre-OUIA)
Content
// Good: Use data-ouia-component-id
Content
// Better: Use ouiaId on PatternFly components
Content
**Note:** The ``data-id`` attribute may still appear in CSS selectors for styling purposes (e.g., ``div.ibutsu-widget-header``), but should never be used for test selectors.
See Also
--------
* :doc:`backend-testing` - Backend testing guide with similar patterns
* `React Testing Library Documentation `_
* `Jest Documentation `_
* `PatternFly Components `_
* ``AGENTS.md`` - Agent instructions including PatternFly OUIA guidance