import { FocusZone, AutoFocusZone } from '@fluentui/react-bindings';
import * as React from 'react';
import * as ReactTestUtils from 'react-dom/test-utils';
// rAF does not exist in node - let's mock it
window.requestAnimationFrame = (callback: FrameRequestCallback) => {
const r = window.setTimeout(callback, 0);
jest.runAllTimers();
return r;
};
const animationFrame = () => new Promise(resolve => window.requestAnimationFrame(resolve));
jest.useFakeTimers();
describe('AutoFocusZone', () => {
let lastFocusedElement: HTMLElement | undefined;
const _onFocus = (ev: any): void => (lastFocusedElement = ev.target);
const setupElement = (
element: HTMLElement,
{
clientRect,
isVisible = true,
}: {
clientRect: {
top: number;
left: number;
bottom: number;
right: number;
};
isVisible?: boolean;
},
): void => {
// @ts-ignore
element.getBoundingClientRect = () => ({
top: clientRect.top,
left: clientRect.left,
bottom: clientRect.bottom,
right: clientRect.right,
width: clientRect.right - clientRect.left,
height: clientRect.bottom - clientRect.top,
});
element.setAttribute('data-is-visible', String(isVisible));
element.focus = () => ReactTestUtils.Simulate.focus(element);
};
beforeEach(() => {
lastFocusedElement = undefined;
});
describe('Focusing the ATZ', () => {
function setupTest(firstFocusableSelector?: string) {
let autoFocusZoneRef: AutoFocusZone | null = null;
const topLevelDiv = ReactTestUtils.renderIntoDocument<{}>(
{
autoFocusZoneRef = ftz;
}}
>
,
) as HTMLElement;
const buttonF = topLevelDiv.querySelector('.f') as HTMLElement;
const buttonA = topLevelDiv.querySelector('.a') as HTMLElement;
const buttonB = topLevelDiv.querySelector('.b') as HTMLElement;
const buttonZ = topLevelDiv.querySelector('.z') as HTMLElement;
// Assign bounding locations to buttons.
setupElement(buttonF, { clientRect: { top: 0, bottom: 10, left: 0, right: 10 } });
setupElement(buttonA, { clientRect: { top: 10, bottom: 20, left: 0, right: 10 } });
setupElement(buttonB, { clientRect: { top: 20, bottom: 30, left: 0, right: 10 } });
setupElement(buttonZ, { clientRect: { top: 30, bottom: 40, left: 0, right: 10 } });
return { autoFocusZone: autoFocusZoneRef, buttonF, buttonA, buttonB, buttonZ };
}
it('goes to first focusable element when focusing the ATZ', async () => {
expect.assertions(1);
const { autoFocusZone, buttonF } = setupTest();
// By calling `componentDidMount`, AFZ will behave as just initialized and focus needed element
// Focus within should go to 1st focusable inner element.
// @ts-ignore
autoFocusZone.componentDidMount();
await animationFrame();
expect(lastFocusedElement).toBe(buttonF);
});
it('goes to the element with containing the firstFocusableSelector if provided when focusing the ATZ', async () => {
expect.assertions(1);
const { autoFocusZone, buttonB } = setupTest('.b');
// By calling `componentDidMount`, AFZ will behave as just initialized and focus needed element
// Focus within should go to the element containing the selector.
// @ts-ignore
autoFocusZone.componentDidMount();
await animationFrame();
expect(lastFocusedElement).toBe(buttonB);
});
});
});