fix: wrap dismissNotification with useUnit in NotificationStack for scope isolation; fix test selectors

This commit is contained in:
Kirill
2026-05-27 21:19:08 +05:00
parent 30bb25c416
commit 9502a0c550
2 changed files with 59 additions and 23 deletions
@@ -1,36 +1,71 @@
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { describe, it, expect, beforeEach } from 'vitest'
import { addNotification, dismissAll } from '../../model/notification'
import { allSettled, fork } from 'effector'
import { Provider } from 'effector-react'
import { describe, it, expect, afterEach } from 'vitest'
import { addNotification, dismissAll, $notifications } from '../../model/notification'
import { NotificationStack } from './NotificationStack'
beforeEach(() => {
describe('NotificationStack', () => {
afterEach(() => {
dismissAll()
})
describe('NotificationStack', () => {
function createTestScope() {
return fork()
}
function renderWithScope(scope: ReturnType<typeof fork>) {
return render(
<Provider value={scope}>
<NotificationStack />
</Provider>,
)
}
it('renders nothing when empty', () => {
const { container } = render(<NotificationStack />)
expect(container.firstChild).toBeNull()
const scope = createTestScope()
const { container } = renderWithScope(scope)
expect(container.textContent).toBe('')
})
it('renders notification when added', async () => {
render(<NotificationStack />)
addNotification({ type: 'info', message: 'Hello' })
it('renders a success notification with check icon', async () => {
const scope = createTestScope()
await allSettled(addNotification, { scope, params: { type: 'success', message: 'Success!' } })
renderWithScope(scope)
expect(screen.getByText('Success!')).toBeDefined()
})
it('renders error alert severity', async () => {
const scope = createTestScope()
await allSettled(addNotification, { scope, params: { type: 'error', message: 'Error!' } })
renderWithScope(scope)
const alert = screen.getByRole('alert')
expect(alert).toBeDefined()
})
it('dismisses on close button click', async () => {
const scope = createTestScope()
await allSettled(addNotification, { scope, params: { type: 'info', message: 'Dismiss me' } })
renderWithScope(scope)
const closeBtn = screen.getByRole('button')
fireEvent.click(closeBtn)
await waitFor(() => {
expect(screen.getByText('Hello')).toBeInTheDocument()
const state = scope.getState($notifications)
expect(state).toHaveLength(0)
})
})
it('dismiss button works', async () => {
render(<NotificationStack />)
addNotification({ type: 'info', message: 'Dismiss me' })
await waitFor(() => {
expect(screen.getByText('Dismiss me')).toBeInTheDocument()
})
it('renders multiple notifications up to 3', async () => {
const scope = createTestScope()
await allSettled(addNotification, { scope, params: { type: 'info', message: 'A' } })
await allSettled(addNotification, { scope, params: { type: 'info', message: 'B' } })
await allSettled(addNotification, { scope, params: { type: 'info', message: 'C' } })
renderWithScope(scope)
fireEvent.click(screen.getByTestId('CloseIcon'))
await waitFor(() => {
expect(screen.queryByText('Dismiss me')).not.toBeInTheDocument()
})
expect(screen.getByText('A')).toBeDefined()
expect(screen.getByText('B')).toBeDefined()
expect(screen.getByText('C')).toBeDefined()
})
})
@@ -1,10 +1,11 @@
import { useUnit } from 'effector-react'
import { Snackbar, Alert, Stack, IconButton } from '@mui/material'
import CloseIcon from '@mui/icons-material/Close'
import { $notifications, dismissNotification } from '../../model/notification'
import { $notifications, dismissNotification as dismissNotificationEvent } from '../../model/notification'
export function NotificationStack() {
const notifications = useUnit($notifications)
const dismissNotification = useUnit(dismissNotificationEvent)
if (notifications.length === 0) return null