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 { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { describe, it, expect, beforeEach } from 'vitest' import { allSettled, fork } from 'effector'
import { addNotification, dismissAll } from '../../model/notification' import { Provider } from 'effector-react'
import { describe, it, expect, afterEach } from 'vitest'
import { addNotification, dismissAll, $notifications } from '../../model/notification'
import { NotificationStack } from './NotificationStack' import { NotificationStack } from './NotificationStack'
beforeEach(() => { describe('NotificationStack', () => {
afterEach(() => {
dismissAll() 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', () => { it('renders nothing when empty', () => {
const { container } = render(<NotificationStack />) const scope = createTestScope()
expect(container.firstChild).toBeNull() const { container } = renderWithScope(scope)
expect(container.textContent).toBe('')
}) })
it('renders notification when added', async () => { it('renders a success notification with check icon', async () => {
render(<NotificationStack />) const scope = createTestScope()
addNotification({ type: 'info', message: 'Hello' }) 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(() => { await waitFor(() => {
expect(screen.getByText('Hello')).toBeInTheDocument() const state = scope.getState($notifications)
expect(state).toHaveLength(0)
}) })
}) })
it('dismiss button works', async () => { it('renders multiple notifications up to 3', async () => {
render(<NotificationStack />) const scope = createTestScope()
addNotification({ type: 'info', message: 'Dismiss me' }) await allSettled(addNotification, { scope, params: { type: 'info', message: 'A' } })
await waitFor(() => { await allSettled(addNotification, { scope, params: { type: 'info', message: 'B' } })
expect(screen.getByText('Dismiss me')).toBeInTheDocument() await allSettled(addNotification, { scope, params: { type: 'info', message: 'C' } })
}) renderWithScope(scope)
fireEvent.click(screen.getByTestId('CloseIcon')) expect(screen.getByText('A')).toBeDefined()
await waitFor(() => { expect(screen.getByText('B')).toBeDefined()
expect(screen.queryByText('Dismiss me')).not.toBeInTheDocument() expect(screen.getByText('C')).toBeDefined()
})
}) })
}) })
@@ -1,10 +1,11 @@
import { useUnit } from 'effector-react' import { useUnit } from 'effector-react'
import { Snackbar, Alert, Stack, IconButton } from '@mui/material' import { Snackbar, Alert, Stack, IconButton } from '@mui/material'
import CloseIcon from '@mui/icons-material/Close' import CloseIcon from '@mui/icons-material/Close'
import { $notifications, dismissNotification } from '../../model/notification' import { $notifications, dismissNotification as dismissNotificationEvent } from '../../model/notification'
export function NotificationStack() { export function NotificationStack() {
const notifications = useUnit($notifications) const notifications = useUnit($notifications)
const dismissNotification = useUnit(dismissNotificationEvent)
if (notifications.length === 0) return null if (notifications.length === 0) return null