fix: wrap dismissNotification with useUnit in NotificationStack for scope isolation; fix test selectors
This commit is contained in:
@@ -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(() => {
|
|
||||||
dismissAll()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('NotificationStack', () => {
|
describe('NotificationStack', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
dismissAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user