Skip to content

Commit 56fce5e

Browse files
committed
chore: Export TestSingleTabStopNavigationProvider to avoid a dependency on RTL
1 parent 1bdc64f commit 56fce5e

File tree

2 files changed

+48
-20
lines changed

2 files changed

+48
-20
lines changed
Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import React, { createRef, forwardRef, useCallback, useImperativeHandle, useRef } from 'react';
4+
import React, { forwardRef, useCallback, useEffect, useRef } from 'react';
55
import { render } from '@testing-library/react';
66

77
import { FocusableChangeHandler, SingleTabStopNavigationContext } from '../';
8+
import { useUniqueId } from '../../use-unique-id';
89

9-
interface ProviderRef {
10+
interface TestProviderAPI {
1011
setCurrentTarget(focusTarget: null | Element, suppressed?: (null | Element)[]): void;
1112
}
1213

13-
const FakeSingleTabStopNavigationProvider = forwardRef(
14-
(
15-
{ children, navigationActive }: { children: React.ReactNode; navigationActive: boolean },
16-
ref: React.Ref<ProviderRef>
17-
) => {
14+
const providerRegistry = new Map<string, TestProviderAPI>();
15+
16+
export const TestSingleTabStopNavigationProvider = forwardRef(
17+
({
18+
children,
19+
navigationActive,
20+
providerId: explicitProviderId,
21+
}: {
22+
children: React.ReactNode;
23+
navigationActive: boolean;
24+
providerId?: string;
25+
}) => {
1826
const focusablesRef = useRef(new Set<Element>());
1927
const focusHandlersRef = useRef(new Map<Element, FocusableChangeHandler>());
2028
const registerFocusable = useCallback((focusable: HTMLElement, changeHandler: FocusableChangeHandler) => {
@@ -26,14 +34,22 @@ const FakeSingleTabStopNavigationProvider = forwardRef(
2634
};
2735
}, []);
2836

29-
useImperativeHandle(ref, () => ({
37+
const providerIdFallback = useUniqueId();
38+
const providerId = explicitProviderId ?? providerIdFallback;
39+
providerRegistry.set(providerId, {
3040
setCurrentTarget: (focusTarget: null | Element, suppressed: Element[] = []) => {
3141
focusablesRef.current.forEach(focusable => {
3242
const handler = focusHandlersRef.current.get(focusable)!;
3343
handler(focusTarget === focusable || suppressed.includes(focusable));
3444
});
3545
},
36-
}));
46+
});
47+
useEffect(
48+
() => () => {
49+
providerRegistry.delete(providerId);
50+
},
51+
[providerId]
52+
);
3753

3854
return (
3955
<SingleTabStopNavigationContext.Provider
@@ -45,24 +61,32 @@ const FakeSingleTabStopNavigationProvider = forwardRef(
4561
}
4662
);
4763

64+
export function getTestProvider(providerId?: string): TestProviderAPI {
65+
return {
66+
setCurrentTarget(focusTarget, suppressed) {
67+
if (providerId) {
68+
providerRegistry.get(providerId)?.setCurrentTarget(focusTarget, suppressed);
69+
} else {
70+
Array.from(providerRegistry).forEach(([, provider]) => provider.setCurrentTarget(focusTarget, suppressed));
71+
}
72+
},
73+
};
74+
}
75+
76+
/**
77+
* @deprecated - Use TestSingleTabStopNavigationProvider instead
78+
*/
4879
export function renderWithSingleTabStopNavigation(
4980
ui: React.ReactNode,
5081
{ navigationActive = true }: { navigationActive?: boolean } = {}
5182
) {
52-
const providerRef = createRef<ProviderRef>();
5383
const { container, rerender } = render(
54-
<FakeSingleTabStopNavigationProvider ref={providerRef} navigationActive={navigationActive}>
55-
{ui}
56-
</FakeSingleTabStopNavigationProvider>
84+
<TestSingleTabStopNavigationProvider navigationActive={navigationActive}>{ui}</TestSingleTabStopNavigationProvider>
5785
);
5886
return {
5987
container,
6088
rerender,
61-
setCurrentTarget: (focusTarget: null | Element, suppressed: (null | Element)[] = []) => {
62-
if (!providerRef.current) {
63-
throw new Error('Provider is not ready');
64-
}
65-
providerRef.current.setCurrentTarget(focusTarget, suppressed);
66-
},
89+
setCurrentTarget: (focusTarget: null | Element, suppressed: (null | Element)[] = []) =>
90+
getTestProvider().setCurrentTarget(focusTarget, suppressed),
6791
};
6892
}

src/internal/testing.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ export { clearOneTimeMetricsCache } from './base-component/metrics/metrics';
55
export { clearMessageCache } from './logging';
66
export { setGlobalFlag } from './global-flags';
77
export { clearVisualRefreshState } from './visual-mode';
8-
export { renderWithSingleTabStopNavigation } from './single-tab-stop/__tests__/utils';
8+
export {
9+
renderWithSingleTabStopNavigation,
10+
TestSingleTabStopNavigationProvider,
11+
getTestProvider,
12+
} from './single-tab-stop/__tests__/utils';

0 commit comments

Comments
 (0)