Skip to content

Commit

Permalink
feat(Tabs): make onBeforeUnload async
Browse files Browse the repository at this point in the history
  • Loading branch information
alexbrillant committed Apr 4, 2022
1 parent df446af commit edd8d02
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 27 deletions.
37 changes: 25 additions & 12 deletions packages/react/src/components/tabs/tabs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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[] {
Expand Down Expand Up @@ -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(<Tabs tabs={tabs} />);

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(<Tabs tabs={tabs} />);

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(<Tabs tabs={tabs} />);

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', () => {
Expand Down
9 changes: 5 additions & 4 deletions packages/react/src/components/tabs/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ export interface Tab {
leftIcon?: IconName;
rightIcon?: IconName;
panelContent: ReactNode;
onBeforeUnload?: () => boolean;
onBeforeUnload?(): Promise<boolean>;
}

interface TabItem extends Tab {
id: string;
panelId: string;
buttonRef: RefObject<HTMLButtonElement>;
onBeforeUnload?: () => boolean;
onBeforeUnload?(): Promise<boolean>;
}

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

function handleTabSelected(tabItem: TabItem): void {
async function handleTabSelected(tabItem: TabItem): Promise<void> {
if (selectedTab?.onBeforeUnload) {
if (selectedTab.onBeforeUnload?.()) {
const isConfirmed = await selectedTab.onBeforeUnload();
if (isConfirmed) {
setSelectedTab(tabItem);
}
} else {
Expand Down
16 changes: 5 additions & 11 deletions packages/storybook/stories/tabs.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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: <StyledDiv>First tab content</StyledDiv>,
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: <StyledDiv>Second tab content</StyledDiv>,
onBeforeUnload: () => {
console.info('second tab unload confirmed');
return true;
},
onBeforeUnload: () => Promise.resolve(true),
},
{
title: 'Third Button',
panelContent: <StyledDiv>Third tab content</StyledDiv>,
onBeforeUnload: () => {
console.info('third tab unload confirmed');
return true;
},
onBeforeUnload: () => Promise.resolve(true),
},
];

Expand Down

0 comments on commit edd8d02

Please sign in to comment.