NestedFolders: stay in the modal whilst actions complete (#69730)
* stay in the modal whilst actions complete * don't return anything here to fix types * ensure we're always resetting button state
This commit is contained in:
@@ -1,10 +1,23 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
import { ConfirmModal } from './ConfirmModal';
|
||||
|
||||
describe('ConfirmModal', () => {
|
||||
const mockOnConfirm = jest.fn();
|
||||
|
||||
let user: ReturnType<typeof userEvent.setup>;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
user = userEvent.setup({ delay: null });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should render correct title, body, dismiss-, alternative- and confirm-text', () => {
|
||||
render(
|
||||
<ConfirmModal
|
||||
@@ -76,7 +89,7 @@ describe('ConfirmModal', () => {
|
||||
dismissText="Dismiss Text"
|
||||
isOpen={true}
|
||||
confirmationText="My confirmation text"
|
||||
onConfirm={() => {}}
|
||||
onConfirm={mockOnConfirm}
|
||||
onDismiss={() => {}}
|
||||
onAlternative={() => {}}
|
||||
/>
|
||||
@@ -85,7 +98,49 @@ describe('ConfirmModal', () => {
|
||||
expect(screen.getByRole('button', { name: 'Please Confirm' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Please Confirm' })).toBeDisabled();
|
||||
|
||||
await userEvent.type(screen.getByPlaceholderText('Type "My confirmation text" to confirm'), 'mY CoNfIrMaTiOn TeXt');
|
||||
expect(screen.getByRole('button', { name: 'Please Confirm' })).not.toBeDisabled();
|
||||
await user.type(screen.getByPlaceholderText('Type "My confirmation text" to confirm'), 'mY CoNfIrMaTiOn TeXt');
|
||||
expect(screen.getByRole('button', { name: 'Please Confirm' })).toBeEnabled();
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Please Confirm' }));
|
||||
expect(mockOnConfirm).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returning a promise in the onConfirm callback disables the button whilst the callback is in progress', async () => {
|
||||
mockOnConfirm.mockImplementation(() => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve('');
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
render(
|
||||
<ConfirmModal
|
||||
title="Some Title"
|
||||
body="Some Body"
|
||||
confirmText="Please Confirm"
|
||||
alternativeText="Alternative Text"
|
||||
dismissText="Dismiss Text"
|
||||
isOpen={true}
|
||||
confirmationText="My confirmation text"
|
||||
onConfirm={mockOnConfirm}
|
||||
onDismiss={() => {}}
|
||||
onAlternative={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByRole('button', { name: 'Please Confirm' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Please Confirm' })).toBeDisabled();
|
||||
|
||||
await user.type(screen.getByPlaceholderText('Type "My confirmation text" to confirm'), 'My confirmation text');
|
||||
expect(screen.getByRole('button', { name: 'Please Confirm' })).toBeEnabled();
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Please Confirm' }));
|
||||
expect(mockOnConfirm).toHaveBeenCalled();
|
||||
expect(screen.getByRole('button', { name: 'Please Confirm' })).toBeDisabled();
|
||||
|
||||
jest.runAllTimers();
|
||||
await waitFor(() => {
|
||||
return expect(screen.getByRole('button', { name: 'Please Confirm' })).toBeEnabled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,8 +37,10 @@ export interface ConfirmModalProps {
|
||||
alternativeText?: string;
|
||||
/** Confirm button variant */
|
||||
confirmButtonVariant?: ButtonVariant;
|
||||
/** Confirm action callback */
|
||||
onConfirm(): void;
|
||||
/** Confirm action callback
|
||||
* Return a promise to disable the confirm button until the promise is resolved
|
||||
*/
|
||||
onConfirm(): void | Promise<void>;
|
||||
/** Dismiss action callback */
|
||||
onDismiss(): void;
|
||||
/** Alternative action callback */
|
||||
@@ -83,6 +85,15 @@ export const ConfirmModal = ({
|
||||
}
|
||||
}, [isOpen, confirmationText]);
|
||||
|
||||
const onConfirmClick = async () => {
|
||||
setDisabled(true);
|
||||
try {
|
||||
await onConfirm();
|
||||
} finally {
|
||||
setDisabled(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal className={cx(styles.modal, modalClass)} title={title} icon={icon} isOpen={isOpen} onDismiss={onDismiss}>
|
||||
<div className={styles.modalText}>
|
||||
@@ -102,7 +113,7 @@ export const ConfirmModal = ({
|
||||
</Button>
|
||||
<Button
|
||||
variant={confirmButtonVariant}
|
||||
onClick={onConfirm}
|
||||
onClick={onConfirmClick}
|
||||
disabled={disabled}
|
||||
ref={buttonRef}
|
||||
data-testid={selectors.pages.ConfirmModal.delete}
|
||||
|
||||
Reference in New Issue
Block a user