176 lines
6.2 KiB
TypeScript
176 lines
6.2 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
|
import SecurityWarning from '../../src/components/SecurityWarning'
|
|
|
|
// Мок для navigator.clipboard
|
|
const mockWriteText = vi.fn()
|
|
Object.assign(navigator, {
|
|
clipboard: {
|
|
writeText: mockWriteText,
|
|
},
|
|
})
|
|
|
|
// Мок для document.execCommand (fallback для старых браузеров)
|
|
const mockExecCommand = vi.fn()
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
document.execCommand = mockExecCommand
|
|
})
|
|
|
|
describe('SecurityWarning', () => {
|
|
const INSTALL_COMMAND = 'bash <(curl -fsSL https://raw.githubusercontent.com/denpiligrim/3dp-manager/main/install.sh)'
|
|
|
|
const renderWarning = () => {
|
|
return render(<SecurityWarning />)
|
|
}
|
|
|
|
describe('рендеринг', () => {
|
|
it('должен рендериться с заголовком предупреждения', () => {
|
|
renderWarning()
|
|
expect(
|
|
screen.getByText(/3DP-MANAGER работает в небезопасном режиме/i)
|
|
).toBeInTheDocument()
|
|
})
|
|
|
|
it('должен отображать предупреждение о паролях', () => {
|
|
renderWarning()
|
|
expect(
|
|
screen.getByText(/Не вводите реальные пароли от 3x-ui панели/i)
|
|
).toBeInTheDocument()
|
|
})
|
|
|
|
it('должен отображать инструкцию по переустановке', () => {
|
|
renderWarning()
|
|
expect(
|
|
screen.getByText(/Для безопасной работы переустановите 3DP-MANAGER с SSL-сертификатами/i)
|
|
).toBeInTheDocument()
|
|
})
|
|
|
|
it('должен отображать команду установки', () => {
|
|
renderWarning()
|
|
expect(screen.getByText(INSTALL_COMMAND)).toBeInTheDocument()
|
|
})
|
|
|
|
it('должен отображать кнопку копирования команды', () => {
|
|
renderWarning()
|
|
expect(screen.getByText('Копировать')).toBeInTheDocument()
|
|
})
|
|
|
|
it('должен отображать иконку копирования', () => {
|
|
renderWarning()
|
|
expect(screen.getByTestId('icon-ContentCopy')).toBeInTheDocument()
|
|
})
|
|
|
|
it('должен иметь семантически правильный Alert', () => {
|
|
renderWarning()
|
|
const alert = screen.getByRole('alert')
|
|
expect(alert).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('копирование команды', () => {
|
|
it('должен копировать команду в буфер обмена при клике', async () => {
|
|
mockWriteText.mockResolvedValue(undefined)
|
|
|
|
renderWarning()
|
|
const copyButton = screen.getByText('Копировать')
|
|
fireEvent.click(copyButton)
|
|
|
|
await waitFor(() => {
|
|
expect(mockWriteText).toHaveBeenCalledWith(INSTALL_COMMAND)
|
|
})
|
|
})
|
|
|
|
it('должен показывать уведомление "Скопировано" после копирования', async () => {
|
|
mockWriteText.mockResolvedValue(undefined)
|
|
|
|
renderWarning()
|
|
const copyButton = screen.getByText('Копировать')
|
|
fireEvent.click(copyButton)
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText('Скопировано')).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
it('должен использовать fallback при отсутствии navigator.clipboard', async () => {
|
|
// Мок ошибки clipboard API
|
|
mockWriteText.mockRejectedValue(new Error('Not supported'))
|
|
|
|
renderWarning()
|
|
const copyButton = screen.getByText('Копировать')
|
|
fireEvent.click(copyButton)
|
|
|
|
await waitFor(() => {
|
|
expect(mockExecCommand).toHaveBeenCalledWith('copy')
|
|
})
|
|
})
|
|
|
|
it('должен показывать уведомление "Скопировано" при использовании fallback', async () => {
|
|
mockWriteText.mockRejectedValue(new Error('Not supported'))
|
|
mockExecCommand.mockReturnValue(true)
|
|
|
|
renderWarning()
|
|
const copyButton = screen.getByText('Копировать')
|
|
fireEvent.click(copyButton)
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText('Скопировано')).toBeInTheDocument()
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Snackbar уведомление', () => {
|
|
it('должен показывать уведомление после копирования', async () => {
|
|
mockWriteText.mockResolvedValue(undefined)
|
|
|
|
renderWarning()
|
|
const copyButton = screen.getByText('Копировать')
|
|
fireEvent.click(copyButton)
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText('Скопировано')).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
it('должен закрывать уведомление при клике на кнопку закрытия', async () => {
|
|
mockWriteText.mockResolvedValue(undefined)
|
|
|
|
renderWarning()
|
|
const copyButton = screen.getByText('Копировать')
|
|
fireEvent.click(copyButton)
|
|
|
|
// Ждём появления уведомления
|
|
await waitFor(() => {
|
|
expect(screen.getByText('Скопировано')).toBeInTheDocument()
|
|
})
|
|
|
|
// Находим кнопку закрытия по иконке Close
|
|
const closeButton = screen.getByTestId('icon-Close').closest('button')
|
|
if (closeButton) {
|
|
fireEvent.click(closeButton)
|
|
}
|
|
|
|
// Уведомление закрыто
|
|
await waitFor(() => {
|
|
expect(screen.queryByText('Скопировано')).not.toBeInTheDocument()
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('стили компонента', () => {
|
|
it('должен иметь variant="filled"', () => {
|
|
renderWarning()
|
|
const alert = screen.getByRole('alert')
|
|
// Проверяем что Alert имеет filled стиль (проверка через классы MUI)
|
|
expect(alert).toHaveClass('MuiAlert-filledWarning')
|
|
})
|
|
|
|
it('должен отображать код в monospace шрифте', () => {
|
|
renderWarning()
|
|
const codeBlock = screen.getByText(INSTALL_COMMAND)
|
|
expect(codeBlock.tagName).toBe('CODE')
|
|
})
|
|
})
|
|
})
|