import type { ReactNode } from 'react' import React from 'react' import { act, render, screen, waitFor } from '@testing-library/react' import Toast, { ToastProvider, useToastContext } from '.' import '@testing-library/jest-dom' import { noop } from 'lodash-es' // Mock timers for testing timeouts jest.useFakeTimers() const TestComponent = () => { const { notify, close } = useToastContext() return (
) } describe('Toast', () => { describe('Toast Component', () => { test('renders toast with correct type and message', () => { render( , ) expect(screen.getByText('Success message')).toBeInTheDocument() }) test('renders with different types', () => { const { rerender } = render( , ) expect(document.querySelector('.text-text-success')).toBeInTheDocument() rerender( , ) expect(document.querySelector('.text-text-destructive')).toBeInTheDocument() }) test('renders with custom component', () => { render( Custom} /> , ) expect(screen.getByTestId('custom-component')).toBeInTheDocument() }) test('renders children content', () => { render( Additional information , ) expect(screen.getByText('Additional information')).toBeInTheDocument() }) test('does not render close button when close is undefined', () => { // Create a modified context where close is undefined const CustomToastContext = React.createContext({ notify: noop, close: undefined }) // Create a wrapper component using the custom context const Wrapper = ({ children }: { children: ReactNode }) => ( {children} ) render( , ) expect(screen.getByText('No close button')).toBeInTheDocument() // Ensure the close button is not rendered expect(document.querySelector('.h-4.w-4.shrink-0.text-text-tertiary')).not.toBeInTheDocument() }) }) describe('ToastProvider and Context', () => { test('shows and hides toast using context', async () => { render( , ) // No toast initially expect(screen.queryByText('Notification message')).not.toBeInTheDocument() // Show toast act(() => { screen.getByText('Show Toast').click() }) expect(screen.getByText('Notification message')).toBeInTheDocument() // Close toast act(() => { screen.getByText('Close Toast').click() }) expect(screen.queryByText('Notification message')).not.toBeInTheDocument() }) test('automatically hides toast after duration', async () => { render( , ) // Show toast act(() => { screen.getByText('Show Toast').click() }) expect(screen.getByText('Notification message')).toBeInTheDocument() // Fast-forward timer act(() => { jest.advanceTimersByTime(3000) // Default for info type is 3000ms }) // Toast should be gone await waitFor(() => { expect(screen.queryByText('Notification message')).not.toBeInTheDocument() }) }) }) describe('Toast.notify static method', () => { test('creates and removes toast from DOM', async () => { act(() => { // Call the static method Toast.notify({ message: 'Static notification', type: 'warning' }) }) // Toast should be in document expect(screen.getByText('Static notification')).toBeInTheDocument() // Fast-forward timer act(() => { jest.advanceTimersByTime(6000) // Default for warning type is 6000ms }) // Toast should be removed await waitFor(() => { expect(screen.queryByText('Static notification')).not.toBeInTheDocument() }) }) test('calls onClose callback after duration', async () => { const onCloseMock = jest.fn() act(() => { Toast.notify({ message: 'Closing notification', type: 'success', onClose: onCloseMock, }) }) // Fast-forward timer act(() => { jest.advanceTimersByTime(3000) // Default for success type is 3000ms }) // onClose should be called await waitFor(() => { expect(onCloseMock).toHaveBeenCalled() }) }) }) })