feat: add CartSnackbar component with tests
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
import { useEffect } from 'react'
|
||||||
|
import Alert from '@mui/material/Alert'
|
||||||
|
import Button from '@mui/material/Button'
|
||||||
|
import Snackbar from '@mui/material/Snackbar'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { useUnit } from 'effector-react'
|
||||||
|
import { $cartSnackOpen, cartDismissed } from '@/shared/model/cart-notifications'
|
||||||
|
|
||||||
|
export function CartSnackbar() {
|
||||||
|
const open = useUnit($cartSnackOpen)
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open) return
|
||||||
|
const timer = setTimeout(() => cartDismissed(), 4000)
|
||||||
|
return () => clearTimeout(timer)
|
||||||
|
}, [open])
|
||||||
|
|
||||||
|
const handleClose = () => cartDismissed()
|
||||||
|
|
||||||
|
const handleGoToCart = () => {
|
||||||
|
cartDismissed()
|
||||||
|
navigate('/cart')
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Snackbar
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
|
||||||
|
autoHideDuration={4000}
|
||||||
|
>
|
||||||
|
<Alert
|
||||||
|
severity="success"
|
||||||
|
onClose={handleClose}
|
||||||
|
action={
|
||||||
|
<Button color="success" size="small" onClick={handleGoToCart}>
|
||||||
|
Перейти в корзину
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Товар добавлен в корзину
|
||||||
|
</Alert>
|
||||||
|
</Snackbar>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { render, screen, fireEvent, act } from '@testing-library/react'
|
||||||
|
import { describe, it, expect, vi } from 'vitest'
|
||||||
|
import { MemoryRouter } from 'react-router-dom'
|
||||||
|
import { cartAdded, cartDismissed } from '@/shared/model/cart-notifications'
|
||||||
|
import { CartSnackbar } from '@/shared/ui/CartSnackbar'
|
||||||
|
|
||||||
|
function renderWithRouter() {
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<CartSnackbar />
|
||||||
|
</MemoryRouter>,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('CartSnackbar', () => {
|
||||||
|
it('is hidden when store is false', () => {
|
||||||
|
cartDismissed()
|
||||||
|
renderWithRouter()
|
||||||
|
expect(screen.queryByText(/товар добавлен/i)).not.toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows snackbar when cartAdded is fired', () => {
|
||||||
|
renderWithRouter()
|
||||||
|
cartAdded()
|
||||||
|
expect(screen.getByText(/товар добавлен/i)).toBeInTheDocument()
|
||||||
|
expect(screen.getByRole('button', { name: /перейти в корзину/i })).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('closes on dismiss button click', () => {
|
||||||
|
renderWithRouter()
|
||||||
|
cartAdded()
|
||||||
|
const closeBtn = screen.getByLabelText(/закрыть/i)
|
||||||
|
fireEvent.click(closeBtn)
|
||||||
|
expect(screen.queryByText(/товар добавлен/i)).not.toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('auto-closes after 4 seconds', () => {
|
||||||
|
vi.useFakeTimers()
|
||||||
|
renderWithRouter()
|
||||||
|
cartAdded()
|
||||||
|
act(() => {
|
||||||
|
vi.advanceTimersByTime(4000)
|
||||||
|
})
|
||||||
|
expect(screen.queryByText(/товар добавлен/i)).not.toBeInTheDocument()
|
||||||
|
vi.useRealTimers()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('navigates to /cart and closes on "Перейти в корзину" click', () => {
|
||||||
|
renderWithRouter()
|
||||||
|
cartAdded()
|
||||||
|
const goBtn = screen.getByRole('button', { name: /перейти в корзину/i })
|
||||||
|
fireEvent.click(goBtn)
|
||||||
|
expect(screen.queryByText(/товар добавлен/i)).not.toBeInTheDocument()
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user