Skip to content

Commit edd8d02

Browse files
committed
feat(Tabs): make onBeforeUnload async
1 parent df446af commit edd8d02

File tree

3 files changed

+35
-27
lines changed

3 files changed

+35
-27
lines changed

packages/react/src/components/tabs/tabs.test.tsx

+25-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ import { ReactWrapper } from 'enzyme';
22
import ReactDOM from 'react-dom';
33
import { findByTestId, getByTestId } from '../../test-utils/enzyme-selectors';
44
import { expectFocusToBeOn } from '../../test-utils/enzyme-utils';
5-
import { mountWithProviders, mountWithTheme, renderWithProviders } from '../../test-utils/renderer';
5+
import {
6+
actAndWaitForEffects,
7+
mountWithProviders,
8+
mountWithTheme,
9+
renderWithProviders,
10+
} from '../../test-utils/renderer';
611
import { Tab, Tabs } from './tabs';
712

813
function givenTabs(amount: number): Tab[] {
@@ -82,44 +87,52 @@ describe('Tabs', () => {
8287
expect(getByTestId(wrapper, 'tab-panel-1').exists()).toBe(false);
8388
});
8489

85-
test('tab panel should not change if onBeforeUnload cancels tab selection', () => {
90+
test('tab panel should not change if onBeforeUnload cancels tab selection', async () => {
8691
const tabs: Tab[] = givenTabs(2);
87-
const shouldConfirmTabUnload = false;
92+
const shouldConfirmTabUnload = Promise.resolve(false);
8893
tabs[0] = {
8994
...tabs[0],
9095
onBeforeUnload: () => shouldConfirmTabUnload,
9196
};
9297
const wrapper = mountWithProviders(<Tabs tabs={tabs} />);
9398

94-
getByTestId(wrapper, 'tab-button-2').simulate('click');
99+
await actAndWaitForEffects(wrapper, () => {
100+
getByTestId(wrapper, 'tab-button-2').prop('onClick')();
101+
});
95102

96-
expectPanelToBeRendered(wrapper, 'tab-panel-1');
103+
expect(getByTestId(wrapper, 'tab-panel-1').exists()).toBe(true);
97104
});
98105

99-
test('tab panel should change if no onBeforeUnload callback was provided', () => {
106+
test('tab panel should change if no onBeforeUnload callback was provided', async () => {
100107
const tabs: Tab[] = givenTabs(2);
101108
tabs[0] = {
102109
...tabs[0],
103110
};
104111
const wrapper = mountWithProviders(<Tabs tabs={tabs} />);
105112

106-
getByTestId(wrapper, 'tab-button-2').simulate('click');
113+
await actAndWaitForEffects(wrapper, () => {
114+
const tabButton = getByTestId(wrapper, 'tab-button-2');
115+
tabButton.prop('onClick')();
116+
});
107117

108-
expectPanelToBeRendered(wrapper, 'tab-panel-2');
118+
expect(getByTestId(wrapper, 'tab-panel-2').exists()).toBeTruthy();
109119
});
110120

111-
test('tab panel should change if onBeforeUnload confirms tab selection', () => {
121+
test('tab panel should change if onBeforeUnload confirms tab selection', async () => {
112122
const tabs: Tab[] = givenTabs(2);
113-
const shouldConfirmTabOnClick = true;
123+
const shouldConfirmTabOnClick = Promise.resolve(true);
114124
tabs[0] = {
115125
...tabs[0],
116126
onBeforeUnload: () => shouldConfirmTabOnClick,
117127
};
118128
const wrapper = mountWithProviders(<Tabs tabs={tabs} />);
119129

120-
getByTestId(wrapper, 'tab-button-2').simulate('click');
130+
await actAndWaitForEffects(wrapper, () => {
131+
const tabButton2 = getByTestId(wrapper, 'tab-button-2');
132+
tabButton2.prop('onClick')();
133+
});
121134

122-
expectPanelToBeRendered(wrapper, 'tab-panel-2');
135+
expect(getByTestId(wrapper, 'tab-panel-2').exists()).toBeTruthy();
123136
});
124137

125138
test('tab-panels should all be initially mounted when forceRenderTabPanels is set to true', () => {

packages/react/src/components/tabs/tabs.tsx

+5-4
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ export interface Tab {
2626
leftIcon?: IconName;
2727
rightIcon?: IconName;
2828
panelContent: ReactNode;
29-
onBeforeUnload?: () => boolean;
29+
onBeforeUnload?(): Promise<boolean>;
3030
}
3131

3232
interface TabItem extends Tab {
3333
id: string;
3434
panelId: string;
3535
buttonRef: RefObject<HTMLButtonElement>;
36-
onBeforeUnload?: () => boolean;
36+
onBeforeUnload?(): Promise<boolean>;
3737
}
3838

3939
interface Props {
@@ -58,9 +58,10 @@ export const Tabs: VoidFunctionComponent<Props> = ({
5858
), [tabs]);
5959
const [selectedTab, setSelectedTab] = useState(tabItems[0]);
6060

61-
function handleTabSelected(tabItem: TabItem): void {
61+
async function handleTabSelected(tabItem: TabItem): Promise<void> {
6262
if (selectedTab?.onBeforeUnload) {
63-
if (selectedTab.onBeforeUnload?.()) {
63+
const isConfirmed = await selectedTab.onBeforeUnload();
64+
if (isConfirmed) {
6465
setSelectedTab(tabItem);
6566
}
6667
} else {

packages/storybook/stories/tabs.stories.tsx

+5-11
Original file line numberDiff line numberDiff line change
@@ -169,28 +169,22 @@ export const Contained: Story = () => {
169169
export const UnloadTabCallback: Story = () => {
170170
const tabs: Tab[] = [
171171
{
172-
title: 'First Button',
172+
title: 'Tab that cannot change because onBeforeUnload resolves to false',
173173
panelContent: <StyledDiv>First tab content</StyledDiv>,
174174
onBeforeUnload: () => {
175-
console.info('cannot change tab because callback return false');
176-
return false;
175+
console.info('cannot change tab because onBeforeUnload promise resolves to false here');
176+
return Promise.resolve(false);
177177
},
178178
},
179179
{
180180
title: 'Second Button',
181181
panelContent: <StyledDiv>Second tab content</StyledDiv>,
182-
onBeforeUnload: () => {
183-
console.info('second tab unload confirmed');
184-
return true;
185-
},
182+
onBeforeUnload: () => Promise.resolve(true),
186183
},
187184
{
188185
title: 'Third Button',
189186
panelContent: <StyledDiv>Third tab content</StyledDiv>,
190-
onBeforeUnload: () => {
191-
console.info('third tab unload confirmed');
192-
return true;
193-
},
187+
onBeforeUnload: () => Promise.resolve(true),
194188
},
195189
];
196190

0 commit comments

Comments
 (0)