diff --git a/packages/components/src/tabs/index.tsx b/packages/components/src/tabs/index.tsx index f83922a8c55f0..cf6443c8bdbeb 100644 --- a/packages/components/src/tabs/index.tsx +++ b/packages/components/src/tabs/index.tsx @@ -174,6 +174,7 @@ function Tabs( { return activeElement === item.element; } ); const previousSelectedTabHadFocus = + typeof previousSelectedId === 'string' && previousSelectedId === activeElement?.id; // If the previously selected tab had focus when the selection changed, diff --git a/packages/components/src/tabs/test/index.tsx b/packages/components/src/tabs/test/index.tsx index 7962a5e1942c5..f8a40b3704a34 100644 --- a/packages/components/src/tabs/test/index.tsx +++ b/packages/components/src/tabs/test/index.tsx @@ -14,6 +14,7 @@ import { useEffect, useState } from '@wordpress/element'; */ import Tabs from '..'; import type { TabsProps } from '../types'; +import { act } from 'react-dom/test-utils'; type Tab = { tabId: string; @@ -1173,64 +1174,79 @@ describe( 'Tabs', () => { } ); } ); describe( 'When `selectedId` is changed by the controlling component', () => { - it( 'should automatically update focus if the selected tab already had focus', async () => { - const { rerender } = render( - - ); - - // Tab key should focus the currently selected tab, which is Beta. - await press.Tab(); - expect( await getSelectedTab() ).toHaveTextContent( 'Beta' ); - expect( await getSelectedTab() ).toHaveFocus(); - - rerender( - - ); - - // When the selected tab is changed, it should automatically receive focus. - expect( await getSelectedTab() ).toHaveTextContent( 'Gamma' ); - expect( await getSelectedTab() ).toHaveFocus(); - } ); - it( 'should not automatically update focus if the selected tab was not already focused', async () => { - const { rerender } = render( - - ); - - expect( await getSelectedTab() ).toHaveTextContent( 'Beta' ); - - // Tab key should focus the currently selected tab, which is Beta. - await press.Tab(); - expect( await getSelectedTab() ).toHaveFocus(); - // Arrow left to focus Alpha, which is not the currently - // selected tab - await press.ArrowLeft(); - - rerender( - - ); - - // When the selected tab is changed, it should not automatically receive focus. - expect( await getSelectedTab() ).toHaveTextContent( 'Gamma' ); - expect( - screen.getByRole( 'tab', { name: 'Alpha' } ) - ).toHaveFocus(); - } ); + describe.each( [ true, false ] )( + 'When `selectOnMove` is `%s`', + ( selectOnMove ) => { + it( 'should move focus to the newly selected tab if the previously selected tab was focused', async () => { + const { rerender } = render( + + ); + + // Tab key should focus the currently selected tab, which is Beta. + await press.Tab(); + expect( await getSelectedTab() ).toHaveTextContent( + 'Beta' + ); + expect( await getSelectedTab() ).toHaveFocus(); + + rerender( + + ); + + // When the selected tab is changed, it should automatically receive focus. + expect( await getSelectedTab() ).toHaveTextContent( + 'Gamma' + ); + expect( await getSelectedTab() ).toHaveFocus(); + } ); + it( 'should not move focus to the newly selected tab if the previously selected tab was not focused', async () => { + const { rerender } = render( + + ); + + expect( await getSelectedTab() ).toHaveTextContent( + 'Beta' + ); + + // Tab key should focus the currently selected tab, which is Beta. + await press.Tab(); + expect( await getSelectedTab() ).toHaveFocus(); + // Focus Alpha, which is not the currently selected tab + // (not the most elegant way, but it does the job). + act( () => + screen.getByRole( 'tab', { name: 'Alpha' } ).focus() + ); + + rerender( + + ); + + // When the selected tab is changed, it should not automatically receive focus. + expect( await getSelectedTab() ).toHaveTextContent( + 'Gamma' + ); + expect( + screen.getByRole( 'tab', { name: 'Alpha' } ) + ).toHaveFocus(); + } ); + } + ); } ); describe( 'When `selectOnMove` is `true`', () => {