Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 0 additions & 21 deletions src/internal/single-tab-stop/__tests__/context.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,6 @@ test('does not override tab index when keyboard navigation is not active', () =>
expect(document.querySelector('#button')).not.toHaveAttribute('tabIndex');
});

test('(legacy coverage) does not override tab index when keyboard navigation is not active', () => {
render(
<TestSingleTabStopNavigationProvider navigationActive={false}>
<Button id="button" />
</TestSingleTabStopNavigationProvider>
);
expect(document.querySelector('#button')).not.toHaveAttribute('tabIndex');
});

test('does not override tab index for suppressed elements', () => {
render(
<TestSingleTabStopNavigationProvider navigationActive={true}>
Expand Down Expand Up @@ -107,18 +98,6 @@ test('overrides tab index when keyboard navigation is active', () => {
expect(document.querySelector('#button2')).toHaveAttribute('tabIndex', '-1');
});

test('(legacy coverage) overrides tab index when keyboard navigation is active', () => {
render(
<TestSingleTabStopNavigationProvider navigationActive={true}>
<Button id="button1" />
<Button id="button2" />
</TestSingleTabStopNavigationProvider>
);
setTestSingleTabStopNavigationTarget(document.querySelector('#button1'));
expect(document.querySelector('#button1')).toHaveAttribute('tabIndex', '0');
expect(document.querySelector('#button2')).toHaveAttribute('tabIndex', '-1');
});

test('does not override explicit tab index with 0', () => {
render(
<TestSingleTabStopNavigationProvider navigationActive={true}>
Expand Down
89 changes: 50 additions & 39 deletions src/internal/single-tab-stop/test-helpers/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import React, { forwardRef, useCallback, useEffect, useRef } from 'react';
import React, { useCallback, useEffect, useRef } from 'react';

import { FocusableChangeHandler, SingleTabStopNavigationContext } from '../';
import { useUniqueId } from '../../use-unique-id';
Expand All @@ -14,44 +14,55 @@ interface TestProviderAPI {

const providerRegistry = new Map<string, TestProviderAPI>();

export const TestSingleTabStopNavigationProvider = forwardRef(
({ children, navigationActive }: { children: React.ReactNode; navigationActive: boolean }) => {
const focusablesRef = useRef(new Set<Element>());
const focusHandlersRef = useRef(new Map<Element, FocusableChangeHandler>());
const registerFocusable = useCallback((focusable: HTMLElement, changeHandler: FocusableChangeHandler) => {
focusablesRef.current.add(focusable);
focusHandlersRef.current.set(focusable, changeHandler);
return () => {
focusablesRef.current.delete(focusable);
focusHandlersRef.current.delete(focusable);
};
}, []);

const providerId = useUniqueId();
providerRegistry.set(providerId, {
setCurrentTarget: (focusTarget, suppressed = []) => {
focusablesRef.current.forEach(focusable => {
const handler = focusHandlersRef.current.get(focusable)!;
handler(focusTarget === focusable || suppressed.includes(focusable));
});
},
});
useEffect(
() => () => {
providerRegistry.delete(providerId);
},
[providerId]
);

return (
<SingleTabStopNavigationContext.Provider
value={{ navigationActive, registerFocusable, resetFocusTarget: () => {} }}
>
{children}
</SingleTabStopNavigationContext.Provider>
);
}
);
export const TestSingleTabStopNavigationProvider = ({
children,
navigationActive,
}: {
children: React.ReactNode;
navigationActive: boolean;
}) => {
const focusablesRef = useRef(new Set<Element>());
const focusHandlersRef = useRef(new Map<Element, FocusableChangeHandler>());
const registerFocusable = useCallback((focusable: HTMLElement, changeHandler: FocusableChangeHandler) => {
focusablesRef.current.add(focusable);
focusHandlersRef.current.set(focusable, changeHandler);
return () => {
focusablesRef.current.delete(focusable);
focusHandlersRef.current.delete(focusable);
};
}, []);

const providerId = useUniqueId();
providerRegistry.set(providerId, {
setCurrentTarget: (focusTarget, suppressed = []) => {
focusablesRef.current.forEach(focusable => {
const handler = focusHandlersRef.current.get(focusable)!;
handler(focusTarget === focusable || suppressed.includes(focusable));
});
},
});
useEffect(
() => () => {
providerRegistry.delete(providerId);
},
[providerId]
);

return (
<SingleTabStopNavigationContext.Provider
value={{
navigationActive,
registerFocusable,
// The reset target feature is not needed in the test provider, and it is
// already tested with the actual provider implementation instead.
// istanbul ignore next
resetFocusTarget: () => {},
}}
>
{children}
</SingleTabStopNavigationContext.Provider>
);
};

export const setTestSingleTabStopNavigationTarget: SetTarget = (focusTarget, suppressed) => {
Array.from(providerRegistry).forEach(([, provider]) => provider.setCurrentTarget(focusTarget, suppressed));
Expand Down
Loading