diff --git a/packages/react/src/components/tabs/tabs.test.tsx b/packages/react/src/components/tabs/tabs.test.tsx index 41721e8fc1..e83211e8a7 100644 --- a/packages/react/src/components/tabs/tabs.test.tsx +++ b/packages/react/src/components/tabs/tabs.test.tsx @@ -2,7 +2,12 @@ import { ReactWrapper } from 'enzyme'; import ReactDOM from 'react-dom'; import { findByTestId, getByTestId } from '../../test-utils/enzyme-selectors'; import { expectFocusToBeOn } from '../../test-utils/enzyme-utils'; -import { mountWithProviders, mountWithTheme, renderWithProviders } from '../../test-utils/renderer'; +import { + actAndWaitForEffects, + mountWithProviders, + mountWithTheme, + renderWithProviders, +} from '../../test-utils/renderer'; import { Tab, Tabs } from './tabs'; function givenTabs(amount: number): Tab[] { @@ -82,44 +87,52 @@ describe('Tabs', () => { expect(getByTestId(wrapper, 'tab-panel-1').exists()).toBe(false); }); - test('tab panel should not change if onBeforeUnload cancels tab selection', () => { + test('tab panel should not change if onBeforeUnload cancels tab selection', async () => { const tabs: Tab[] = givenTabs(2); - const shouldConfirmTabUnload = false; + const shouldConfirmTabUnload = Promise.resolve(false); tabs[0] = { ...tabs[0], onBeforeUnload: () => shouldConfirmTabUnload, }; const wrapper = mountWithProviders(); - getByTestId(wrapper, 'tab-button-2').simulate('click'); + await actAndWaitForEffects(wrapper, () => { + getByTestId(wrapper, 'tab-button-2').prop('onClick')(); + }); - expectPanelToBeRendered(wrapper, 'tab-panel-1'); + expect(getByTestId(wrapper, 'tab-panel-1').exists()).toBe(true); }); - test('tab panel should change if no onBeforeUnload callback was provided', () => { + test('tab panel should change if no onBeforeUnload callback was provided', async () => { const tabs: Tab[] = givenTabs(2); tabs[0] = { ...tabs[0], }; const wrapper = mountWithProviders(); - getByTestId(wrapper, 'tab-button-2').simulate('click'); + await actAndWaitForEffects(wrapper, () => { + const tabButton = getByTestId(wrapper, 'tab-button-2'); + tabButton.prop('onClick')(); + }); - expectPanelToBeRendered(wrapper, 'tab-panel-2'); + expect(getByTestId(wrapper, 'tab-panel-2').exists()).toBeTruthy(); }); - test('tab panel should change if onBeforeUnload confirms tab selection', () => { + test('tab panel should change if onBeforeUnload confirms tab selection', async () => { const tabs: Tab[] = givenTabs(2); - const shouldConfirmTabOnClick = true; + const shouldConfirmTabOnClick = Promise.resolve(true); tabs[0] = { ...tabs[0], onBeforeUnload: () => shouldConfirmTabOnClick, }; const wrapper = mountWithProviders(); - getByTestId(wrapper, 'tab-button-2').simulate('click'); + await actAndWaitForEffects(wrapper, () => { + const tabButton2 = getByTestId(wrapper, 'tab-button-2'); + tabButton2.prop('onClick')(); + }); - expectPanelToBeRendered(wrapper, 'tab-panel-2'); + expect(getByTestId(wrapper, 'tab-panel-2').exists()).toBeTruthy(); }); test('tab-panels should all be initially mounted when forceRenderTabPanels is set to true', () => { diff --git a/packages/react/src/components/tabs/tabs.tsx b/packages/react/src/components/tabs/tabs.tsx index 32df277e9c..4ecc3d88e2 100644 --- a/packages/react/src/components/tabs/tabs.tsx +++ b/packages/react/src/components/tabs/tabs.tsx @@ -26,14 +26,14 @@ export interface Tab { leftIcon?: IconName; rightIcon?: IconName; panelContent: ReactNode; - onBeforeUnload?: () => boolean; + onBeforeUnload?(): Promise; } interface TabItem extends Tab { id: string; panelId: string; buttonRef: RefObject; - onBeforeUnload?: () => boolean; + onBeforeUnload?(): Promise; } interface Props { @@ -58,9 +58,10 @@ export const Tabs: VoidFunctionComponent = ({ ), [tabs]); const [selectedTab, setSelectedTab] = useState(tabItems[0]); - function handleTabSelected(tabItem: TabItem): void { + async function handleTabSelected(tabItem: TabItem): Promise { if (selectedTab?.onBeforeUnload) { - if (selectedTab.onBeforeUnload?.()) { + const isConfirmed = await selectedTab.onBeforeUnload(); + if (isConfirmed) { setSelectedTab(tabItem); } } else { diff --git a/packages/storybook/stories/tabs.stories.tsx b/packages/storybook/stories/tabs.stories.tsx index bec2d718fa..11e05bfc5c 100644 --- a/packages/storybook/stories/tabs.stories.tsx +++ b/packages/storybook/stories/tabs.stories.tsx @@ -169,28 +169,22 @@ export const Contained: Story = () => { export const UnloadTabCallback: Story = () => { const tabs: Tab[] = [ { - title: 'First Button', + title: 'Tab that cannot change because onBeforeUnload resolves to false', panelContent: First tab content, onBeforeUnload: () => { - console.info('cannot change tab because callback return false'); - return false; + console.info('cannot change tab because onBeforeUnload promise resolves to false here'); + return Promise.resolve(false); }, }, { title: 'Second Button', panelContent: Second tab content, - onBeforeUnload: () => { - console.info('second tab unload confirmed'); - return true; - }, + onBeforeUnload: () => Promise.resolve(true), }, { title: 'Third Button', panelContent: Third tab content, - onBeforeUnload: () => { - console.info('third tab unload confirmed'); - return true; - }, + onBeforeUnload: () => Promise.resolve(true), }, ];