Skip to content

Commit ac26a80

Browse files
committed
test: improve test coverage for ToastManager
1 parent 76abe05 commit ac26a80

File tree

2 files changed

+165
-6
lines changed

2 files changed

+165
-6
lines changed

packages/react/src/toast/ToastManager.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,19 +222,15 @@ const ToastManager = (inProps) => {
222222
containerRef={containerRef}
223223
>
224224
{Object.keys(state).map((placement) => {
225-
const toasts = ensureArray(state[placement]);
225+
const toasts = ensureArray(state[placement]).filter(toast => !isNullish(toast));
226226
return (
227227
<ToastContainerComponent
228228
key={placement}
229229
placement={placement}
230230
{...ToastContainerProps}
231231
>
232232
<ToastTransitionGroup>
233-
{ensureArray(toasts).map((toast) => {
234-
if (!toast || isNullish(toast.id)) {
235-
// TODO: log an error if the toast id is missing
236-
return null;
237-
}
233+
{toasts.map((toast) => {
238234
const onClose = createCloseToastHandler(toast.id, placement);
239235
return (
240236
<TransitionComponent

packages/react/src/toast/__tests__/ToastManager.test.js

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,10 @@ describe('ToastManager', () => {
516516
});
517517
expect(updateSuccess).toBe(true);
518518
}, [toast]);
519+
const handleClickUpdateInvalidToast = useCallback(() => {
520+
const updateSuccess = toast.update(null, {});
521+
expect(updateSuccess).toBe(false);
522+
}, [toast]);
519523

520524
return (
521525
<>
@@ -525,6 +529,9 @@ describe('ToastManager', () => {
525529
<Button onClick={handleClickUpdateToast}>
526530
Update Toast
527531
</Button>
532+
<Button onClick={handleClickUpdateInvalidToast}>
533+
Update Invalid Toast
534+
</Button>
528535
</>
529536
);
530537
};
@@ -540,9 +547,165 @@ describe('ToastManager', () => {
540547

541548
// Update the toast
542549
await user.click(screen.getByText('Update Toast'));
550+
await user.click(screen.getByText('Update Invalid Toast'));
543551

544552
// Check if the content has been updated
545553
const toastElement = screen.getByTestId(toastId);
546554
expect(toastElement).toHaveTextContent(updatedMessage);
547555
});
556+
557+
it('should not create a toast and return false for invalid placement', async () => {
558+
const user = userEvent.setup();
559+
const toastId = 'toast-id';
560+
const placement = 'center'; // "center" is not a supported placement
561+
const message = 'This is a toast message';
562+
563+
// Spy on console.error to capture and check the error message
564+
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
565+
566+
const WrapperComponent = (props) => (
567+
<ToastManager {...props} />
568+
);
569+
570+
const TestComponent = () => {
571+
const toast = useToastManager();
572+
const handleClick = useCallback(() => {
573+
const result = toast(({ onClose }) => (
574+
<Toast
575+
appearance="error"
576+
isClosable
577+
onClose={onClose}
578+
data-testid={toastId}
579+
>
580+
{message}
581+
</Toast>
582+
), { placement });
583+
expect(result).toBe(false);
584+
}, [toast]);
585+
586+
return (
587+
<Button onClick={handleClick}>
588+
Add Toast
589+
</Button>
590+
);
591+
};
592+
593+
render(
594+
<WrapperComponent>
595+
<TestComponent />
596+
</WrapperComponent>
597+
);
598+
599+
const button = await screen.findByText('Add Toast');
600+
await user.click(button);
601+
602+
// Check that console.error was called with the expected error message
603+
const placements = [
604+
'bottom',
605+
'bottom-right',
606+
'bottom-left',
607+
'top',
608+
'top-left',
609+
'top-right',
610+
];
611+
const expectedErrorMessage = `[ToastManager] Error: Invalid toast placement "${placement}". Please provide a valid placement from the following options: ${placements.join(', ')}.`;
612+
expect(consoleErrorSpy).toHaveBeenCalledWith(expectedErrorMessage);
613+
614+
// Assert that no toast element with the invalid placement was created
615+
const toastElement = screen.queryByTestId(toastId);
616+
expect(toastElement).not.toBeInTheDocument();
617+
618+
// Restore console.error to its original implementation
619+
consoleErrorSpy.mockRestore();
620+
});
621+
622+
it('should create toasts in the correct order for top and bottom placements in the state', async () => {
623+
const user = userEvent.setup();
624+
const topPlacement = 'top';
625+
const bottomPlacement = 'bottom';
626+
const message = 'This is a toast message';
627+
628+
const WrapperComponent = (props) => (
629+
<ToastManager {...props} />
630+
);
631+
632+
const TestComponent = () => {
633+
const toast = useToastManager();
634+
const handleClickAddToasts = useCallback(() => {
635+
// Add toast for top-right placement
636+
toast(({ onClose }) => (
637+
<Toast
638+
appearance="success"
639+
isClosable
640+
onClose={onClose}
641+
>
642+
{message}
643+
</Toast>
644+
), { placement: topPlacement });
645+
646+
// Add toast for bottom-right placement
647+
toast(({ onClose }) => (
648+
<Toast
649+
appearance="success"
650+
isClosable
651+
onClose={onClose}
652+
>
653+
{message}
654+
</Toast>
655+
), { placement: bottomPlacement });
656+
}, [toast]);
657+
658+
return (
659+
<>
660+
<Button onClick={handleClickAddToasts}>Add Toasts</Button>
661+
{/* Access toast.state here to check order */}
662+
{toast.state && (
663+
<pre data-testid="toast-state">{JSON.stringify(toast.state, null, 2)}</pre>
664+
)}
665+
</>
666+
);
667+
};
668+
669+
render(
670+
<WrapperComponent>
671+
<TestComponent />
672+
</WrapperComponent>
673+
);
674+
675+
const button = await screen.findByText('Add Toasts');
676+
await user.click(button);
677+
await user.click(button);
678+
679+
// Wait for the state to be updated with toasts
680+
await screen.findByTestId('toast-state');
681+
682+
// Get the state of the toasts
683+
const toastState = JSON.parse(screen.getByTestId('toast-state').textContent);
684+
685+
// Check that toasts with top-right and bottom-right placements exist in the state
686+
const topToasts = toastState[topPlacement];
687+
const bottomToasts = toastState[bottomPlacement];
688+
689+
// top-right
690+
//
691+
// ```js
692+
// [
693+
// { id: '3', placement: 'top-right' },
694+
// { id: '1', placement: 'top-right' },
695+
// ]
696+
// ```
697+
expect(topToasts).toHaveLength(2);
698+
expect(topToasts[0].id > topToasts[1].id).toBeTruthy();
699+
700+
// bottom-right
701+
//
702+
// ```js
703+
// [
704+
// { id: '2', placement: 'bottom-right' },
705+
// { id: '4', placement: 'bottom-right' },
706+
// ]
707+
// ```
708+
expect(bottomToasts).toHaveLength(2);
709+
expect(bottomToasts[0].id < bottomToasts[1].id).toBeTruthy();
710+
});
548711
});

0 commit comments

Comments
 (0)