Files
3x-ui/frontend/src/test/node-list-a11y.test.tsx
T
Alireza Ahmadi e2184777a0 fix(frontend): make the panel usable with screen readers (#6907)
* fix(frontend): make the panel usable with screen readers

* fix(frontend): keep mobile tab names and the inbound expiry hint

Review of #6907 found two gaps in the screen-reader pass:

- On phone-width screens catTabLabel renders only the icon and names the
  tab by putting aria-label on it, but callers now pass that icon with
  aria-hidden for the desktop label, so every Settings, Xray and Host
  category tab lost its name under TalkBack. catTabLabel now clears
  aria-hidden on the icon it uses as the name.
- DateTimePicker forwarded id and aria-label but not aria-describedby,
  so the inbound expiry hint ("leave blank to never expire") was never
  attached. It now forwards it on both the Gregorian and Jalali input.
2026-10-23 18:29:47 +02:00

57 lines
1.4 KiB
TypeScript

import { screen } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import NodeList from '@/pages/nodes/NodeList';
import type { NodeRecord } from '@/schemas/node';
import { renderWithProviders } from './test-utils';
const noop = () => {};
const failing: NodeRecord = {
id: 1,
name: 'edge',
guid: 'e1',
transitive: false,
enable: true,
status: 'offline',
lastError: 'dial tcp 10.0.0.2:2053: i/o timeout',
};
function renderList(isMobile: boolean) {
renderWithProviders(
<NodeList
nodes={[failing]}
isMobile={isMobile}
selectedIds={[]}
onSelectionChange={noop}
onAdd={noop}
onMtls={noop}
onEdit={noop}
onDelete={noop}
onProbe={noop}
onToggleEnable={noop}
onUpdateNode={noop}
onUpdateSelected={noop}
/>,
);
}
// The error lived only in a hover tooltip and the enable switch had no name, so a
// screen reader heard "exclamation-circle" and "switch" (s-ui#1293).
describe('NodeList screen-reader names', () => {
it('announces the node error from the status column', () => {
renderList(false);
expect(screen.getByRole('img', { name: failing.lastError }).tagName).toBe('SPAN');
});
it.each([false, true])('names the enable switch (mobile=%s)', (isMobile) => {
renderList(isMobile);
expect(screen.getByRole('switch', { name: 'Enabled' }).getAttribute('aria-checked')).toBe(
'true',
);
});
});