PatternFly 6 Switch Component Testing Patterns¶
Last Updated: 2025-10-09 Applies To: PatternFly 6 Switch components in LiteMaaS frontend
Overview¶
PatternFly 6 Switch components use role="switch" (NOT role="checkbox"). This is a critical distinction for testing and differs from native HTML checkboxes.
Discovery Context¶
During Phase 2 of test coverage improvement, we discovered that tests using getByRole('checkbox') to query Switch components were failing. PatternFly 6 Switch components implement the ARIA switch role for better accessibility compliance.
Issue Encountered:
// ❌ WRONG - This will fail
const switches = screen.getAllByRole('checkbox')
// Error: Unable to find an accessible element with the role "checkbox"
Correct Solution:
Testing Switch Components¶
Basic Switch Query¶
import { render, screen } from '@testing-library/react';
import { Switch } from '@patternfly/react-core';
it('should find switch by role', () => {
render(
<Switch
id="my-switch"
label="Enable Feature"
isChecked={false}
onChange={() => {}}
/>
);
// Query by switch role
const switchElement = screen.getByRole('switch');
expect(switchElement).toBeInTheDocument();
});
Multiple Switches¶
it('should find all switches', () => {
render(
<div>
<Switch id="switch-1" label="Option 1" isChecked={false} onChange={() => {}} />
<Switch id="switch-2" label="Option 2" isChecked={true} onChange={() => {}} />
<Switch id="switch-3" label="Option 3" isChecked={false} onChange={() => {}} />
</div>
);
const switches = screen.getAllByRole('switch');
expect(switches).toHaveLength(3);
});
Checking Switch State¶
it('should check if switch is checked', () => {
render(
<Switch
id="my-switch"
label="Enable Feature"
isChecked={true}
onChange={() => {}}
/>
);
const switchElement = screen.getByRole('switch');
expect(switchElement).toBeChecked();
});
it('should check if switch is unchecked', () => {
render(
<Switch
id="my-switch"
label="Enable Feature"
isChecked={false}
onChange={() => {}}
/>
);
const switchElement = screen.getByRole('switch');
expect(switchElement).not.toBeChecked();
});
Testing Switch Interactions¶
import userEvent from '@testing-library/user-event';
it('should toggle switch when clicked', async () => {
const handleChange = vi.fn();
const user = userEvent.setup();
render(
<Switch
id="my-switch"
label="Enable Feature"
isChecked={false}
onChange={(event, checked) => handleChange(checked)}
/>
);
const switchElement = screen.getByRole('switch');
expect(switchElement).not.toBeChecked();
await user.click(switchElement);
expect(handleChange).toHaveBeenCalledWith(true);
});
Testing Disabled Switches¶
it('should not allow interaction when disabled', async () => {
const handleChange = vi.fn();
const user = userEvent.setup();
render(
<Switch
id="my-switch"
label="Enable Feature"
isChecked={false}
isDisabled={true}
onChange={handleChange}
/>
);
const switchElement = screen.getByRole('switch');
expect(switchElement).toBeDisabled();
await user.click(switchElement);
// Should not trigger onChange
expect(handleChange).not.toHaveBeenCalled();
});
Real-World Example: Role Management¶
From UserEditModal.test.tsx:
describe('Role Management', () => {
it('should display role switches for admin users', () => {
const user = createMockUser();
renderWithAuth(
<UserEditModal user={user} canEdit={true} onClose={mockOnClose} onSave={mockOnSave} />,
{ user: mockAdminUser },
);
// Get all switches - there should be 3 role switches (PatternFly Switch uses role="switch")
const switches = screen.getAllByRole('switch');
expect(switches).toHaveLength(3);
});
it('should pre-select user roles correctly', () => {
const user = createMockUser({ roles: ['user', 'admin'] });
renderWithAuth(
<UserEditModal user={user} canEdit={true} onClose={mockOnClose} onSave={mockOnSave} />,
{ user: mockAdminUser },
);
// Get all switches - 2 should be checked (user and admin)
const switches = screen.getAllByRole('switch');
const checkedSwitches = switches.filter((sw) => (sw as HTMLInputElement).checked);
expect(checkedSwitches).toHaveLength(2);
});
it('should toggle role when switch is clicked', async () => {
const user = createMockUser({ roles: ['user'] });
const userEvent = await import('@testing-library/user-event').then((m) => m.default.setup());
renderWithAuth(
<UserEditModal user={user} canEdit={true} onClose={mockOnClose} onSave={mockOnSave} />,
{ user: mockAdminUser },
);
const switches = screen.getAllByRole('switch');
// Find the admin switch (should be the second one - index 1)
const adminSwitch = switches[1];
expect(adminSwitch).not.toBeChecked();
await userEvent.click(adminSwitch);
expect(adminSwitch).toBeChecked();
});
});
Accessibility Notes¶
Why role="switch" Instead of role="checkbox"?¶
PatternFly 6 uses role="switch" for better semantic meaning:
- Switch: Represents an on/off toggle (binary state)
- Checkbox: Represents a selection from a set (can be part of a group)
From an accessibility perspective:
- Screen readers announce "switch" controls differently than "checkbox" controls
- The switch role better communicates the immediate state change behavior
- Follows ARIA 1.2+ best practices
ARIA Attributes on PatternFly Switch¶
PatternFly Switch components include:
<button role="switch" aria-checked="true" aria-label="Enable Feature" class="pf-v6-c-switch">
<!-- switch content -->
</button>
Common Pitfalls¶
❌ Using Checkbox Role¶
❌ Querying by Input Element¶
// Switch is not an input element, it's a button with role="switch"
const switchElement = screen.getByRole('input')
❌ Using Label Text Without Proper Query¶
// May not work as expected - use aria-label or role query
const switchElement = screen.getByLabelText('Enable Feature')
Best Practices¶
✅ Always Use role="switch"¶
✅ Test Both Checked States¶
✅ Test Disabled State¶
✅ Verify onChange Behavior¶
Read-Only Mode Testing¶
When switches are not rendered (read-only view):
it('should not render switches in read-only mode', () => {
renderWithAuth(
<UserEditModal user={user} canEdit={false} onClose={mockOnClose} onSave={mockOnSave} />,
{ user: mockAdminUser },
);
// Switches should not be present in read-only mode
expect(screen.queryByRole('switch')).not.toBeInTheDocument();
});
Related Documentation¶
- PatternFly 6 Switch Component Docs
- ARIA Switch Role Spec
- Testing Library Queries
- Modal Testing Patterns
- Dropdown Testing Patterns
See Also¶
- Context-Dependent Components - For components requiring specific parent props
- Modals - For testing components within modal dialogs
- Dropdowns & Pagination - For other PatternFly 6 interactive components