// @vitest-environment nuxt import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { useSnackbar } from '../use-snackbar'; describe('useSnackbar', () => { beforeEach(() => { useNuxtApp().payload.state = {}; vi.useFakeTimers(); const { resetSnackbar } = useSnackbar(); resetSnackbar(); }); afterEach(() => { vi.useRealTimers(); }); it('дефолтное состояние', () => { const { snackbarText, snackbarIcon, snackbarHighlight, snackbarActionText } = useSnackbar(); expect(snackbarText.value).toBe(''); expect(snackbarIcon.value).toBe('check'); expect(snackbarHighlight.value).toBe(''); expect(snackbarActionText.value).toBe(''); }); it('show показывает и авто-сбрасывает через 4000мс', () => { const { show, snackbarText, snackbarIcon } = useSnackbar(); show('Done'); expect(snackbarText.value).toBe('Done'); expect(snackbarIcon.value).toBe('check'); vi.advanceTimersByTime(3999); expect(snackbarText.value).toBe('Done'); vi.advanceTimersByTime(1); expect(snackbarText.value).toBe(''); }); it('showError показывает и авто-сбрасывает через 4000мс', () => { const { showError, snackbarText, snackbarIcon } = useSnackbar(); showError('Error!'); expect(snackbarText.value).toBe('Error!'); expect(snackbarIcon.value).toBe('close'); vi.advanceTimersByTime(3999); expect(snackbarText.value).toBe('Error!'); vi.advanceTimersByTime(1); expect(snackbarText.value).toBe(''); }); it('setErrorState нормализует ошибку и показывает её', () => { const { setErrorState, snackbarIcon, snackbarText } = useSnackbar(); setErrorState({ message: 'Something failed' }); expect(snackbarIcon.value).toBe('close'); expect(snackbarText.value).toBe('Something failed'); }); it('повторный показ сбрасывает предыдущий таймер', () => { const { showError, snackbarText } = useSnackbar(); showError('First'); vi.advanceTimersByTime(2000); showError('Second'); expect(snackbarText.value).toBe('Second'); vi.advanceTimersByTime(4000); expect(snackbarText.value).toBe(''); }); it('опции задают иконку и подсветку', () => { const { show, snackbarIcon, snackbarHighlight } = useSnackbar(); show('Unfollowed', { icon: 'minus', highlight: 'Top To Bottom' }); expect(snackbarIcon.value).toBe('minus'); expect(snackbarHighlight.value).toBe('Top To Bottom'); }); it('onAction включает кнопку с ключом undo по умолчанию и держит снекбар 6000мс', () => { const { show, snackbarActionText, snackbarText } = useSnackbar(); show('Unfollowed', { onAction: () => {} }); expect(snackbarActionText.value).toBe('undo'); vi.advanceTimersByTime(5999); expect(snackbarText.value).toBe('Unfollowed'); vi.advanceTimersByTime(1); expect(snackbarText.value).toBe(''); expect(snackbarActionText.value).toBe(''); }); it('actionText переопределяет ключ подписи кнопки', () => { const { show, snackbarActionText } = useSnackbar(); show('Video removed', { onAction: () => {}, actionText: 'restore' }); expect(snackbarActionText.value).toBe('restore'); }); it('без onAction кнопки нет', () => { const { show, snackbarActionText } = useSnackbar(); show('Done'); expect(snackbarActionText.value).toBe(''); }); it('runSnackbarAction вызывает колбэк и закрывает снекбар', () => { const { show, runSnackbarAction, snackbarText, snackbarActionText } = useSnackbar(); const undo = vi.fn(); show('Unfollowed', { onAction: undo }); runSnackbarAction(); expect(undo).toHaveBeenCalledTimes(1); expect(snackbarText.value).toBe(''); expect(snackbarActionText.value).toBe(''); runSnackbarAction(); expect(undo).toHaveBeenCalledTimes(1); }); it('новый показ без onAction сбрасывает предыдущий колбэк', () => { const { show, runSnackbarAction } = useSnackbar(); const undo = vi.fn(); show('Unfollowed', { onAction: undo }); show('Done'); runSnackbarAction(); expect(undo).not.toHaveBeenCalled(); }); it('pauseDismiss останавливает автозакрытие', () => { const { show, pauseDismiss, snackbarText } = useSnackbar(); show('Done'); vi.advanceTimersByTime(1000); pauseDismiss(); vi.advanceTimersByTime(60_000); expect(snackbarText.value).toBe('Done'); }); it('resumeDismiss добирает остаток, а не начинает заново', () => { const { show, pauseDismiss, resumeDismiss, snackbarText } = useSnackbar(); show('Done'); vi.advanceTimersByTime(3000); pauseDismiss(); vi.advanceTimersByTime(10_000); resumeDismiss(); vi.advanceTimersByTime(999); expect(snackbarText.value).toBe('Done'); vi.advanceTimersByTime(1); expect(snackbarText.value).toBe(''); }); it('повторная пауза не съедает остаток дважды', () => { const { show, pauseDismiss, resumeDismiss, snackbarText } = useSnackbar(); show('Done'); vi.advanceTimersByTime(1000); pauseDismiss(); vi.advanceTimersByTime(5000); pauseDismiss(); resumeDismiss(); vi.advanceTimersByTime(2999); expect(snackbarText.value).toBe('Done'); vi.advanceTimersByTime(1); expect(snackbarText.value).toBe(''); }); it('resumeDismiss без показанного снекбара ничего не запускает', () => { const { resumeDismiss, snackbarText } = useSnackbar(); resumeDismiss(); vi.advanceTimersByTime(10_000); expect(snackbarText.value).toBe(''); }); it('новый show перебивает паузу предыдущего снекбара', () => { const { show, pauseDismiss, snackbarText } = useSnackbar(); show('First'); pauseDismiss(); show('Second'); vi.advanceTimersByTime(4000); expect(snackbarText.value).toBe(''); }); it('onDismiss срабатывает, когда окно отмены истекло', () => { const { show } = useSnackbar(); const commit = vi.fn(); show('Deleted', { onAction: () => {}, onDismiss: commit }); vi.advanceTimersByTime(5999); expect(commit).not.toHaveBeenCalled(); vi.advanceTimersByTime(1); expect(commit).toHaveBeenCalledTimes(1); }); it('нажатый undo отменяет onDismiss', () => { const { show, runSnackbarAction } = useSnackbar(); const commit = vi.fn(); const undo = vi.fn(); show('Deleted', { onAction: undo, onDismiss: commit }); runSnackbarAction(); vi.advanceTimersByTime(60_000); expect(undo).toHaveBeenCalledTimes(1); expect(commit).not.toHaveBeenCalled(); }); it('новый снекбар сразу выполняет отложенное действие предыдущего', () => { const { show } = useSnackbar(); const commit = vi.fn(); show('Deleted', { onAction: () => {}, onDismiss: commit }); show('Deleted', { onAction: () => {} }); expect(commit).toHaveBeenCalledTimes(1); }); it('пауза на ховере продлевает окно отмены вместе с запросом', () => { const { show, pauseDismiss, resumeDismiss } = useSnackbar(); const commit = vi.fn(); show('Deleted', { onAction: () => {}, onDismiss: commit }); vi.advanceTimersByTime(3000); pauseDismiss(); vi.advanceTimersByTime(60_000); expect(commit).not.toHaveBeenCalled(); resumeDismiss(); vi.advanceTimersByTime(3000); expect(commit).toHaveBeenCalledTimes(1); }); it('resetSnackbar сбрасывает всё', () => { const { show, resetSnackbar, snackbarText, snackbarIcon, snackbarHighlight, snackbarActionText } = useSnackbar(); show('Unfollowed', { icon: 'minus', highlight: 'Top To Bottom', onAction: () => {} }); resetSnackbar(); expect(snackbarText.value).toBe(''); expect(snackbarIcon.value).toBe('check'); expect(snackbarHighlight.value).toBe(''); expect(snackbarActionText.value).toBe(''); }); });