mirror of
https://github.com/php-flasher/php-flasher.git
synced 2026-03-31 15:07:47 +01:00
192 lines
6.3 KiB
TypeScript
192 lines
6.3 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
import type { Envelope } from '@flasher/flasher/types'
|
|
|
|
// Mock SCSS imports
|
|
vi.mock('@flasher/flasher/themes/flasher/flasher.scss', () => ({}))
|
|
|
|
// Import theme after mocking
|
|
import { flasherTheme } from '@flasher/flasher/themes/flasher/flasher'
|
|
|
|
const createEnvelope = (overrides: Partial<Envelope> = {}): Envelope => ({
|
|
type: 'success',
|
|
message: 'Test message',
|
|
title: 'Test title',
|
|
options: {},
|
|
metadata: { plugin: 'theme.flasher' },
|
|
...overrides,
|
|
})
|
|
|
|
describe('flasherTheme', () => {
|
|
describe('render function', () => {
|
|
it('should return valid HTML string', () => {
|
|
const html = flasherTheme.render(createEnvelope())
|
|
|
|
expect(html).toContain('fl-flasher')
|
|
expect(html).toContain('fl-success')
|
|
})
|
|
|
|
it('should include message and title', () => {
|
|
const html = flasherTheme.render(createEnvelope({
|
|
title: 'My Title',
|
|
message: 'My Message',
|
|
}))
|
|
|
|
expect(html).toContain('My Title')
|
|
expect(html).toContain('My Message')
|
|
})
|
|
|
|
it('should apply type-specific class', () => {
|
|
const types = ['success', 'error', 'warning', 'info']
|
|
|
|
types.forEach((type) => {
|
|
const html = flasherTheme.render(createEnvelope({ type }))
|
|
expect(html).toContain(`fl-${type}`)
|
|
})
|
|
})
|
|
|
|
it('should capitalize type for default title when title is empty', () => {
|
|
const html = flasherTheme.render(createEnvelope({
|
|
type: 'success',
|
|
title: '',
|
|
}))
|
|
|
|
expect(html).toContain('Success')
|
|
})
|
|
|
|
it('should include close button', () => {
|
|
const html = flasherTheme.render(createEnvelope())
|
|
|
|
expect(html).toContain('fl-close')
|
|
expect(html).toContain('×')
|
|
})
|
|
|
|
it('should include progress bar container', () => {
|
|
const html = flasherTheme.render(createEnvelope())
|
|
|
|
expect(html).toContain('fl-progress-bar')
|
|
})
|
|
|
|
it('should include icon container', () => {
|
|
const html = flasherTheme.render(createEnvelope())
|
|
|
|
expect(html).toContain('fl-icon')
|
|
})
|
|
})
|
|
|
|
describe('accessibility', () => {
|
|
it('should have role="alert" for error type', () => {
|
|
const html = flasherTheme.render(createEnvelope({ type: 'error' }))
|
|
|
|
expect(html).toContain('role="alert"')
|
|
})
|
|
|
|
it('should have role="alert" for warning type', () => {
|
|
const html = flasherTheme.render(createEnvelope({ type: 'warning' }))
|
|
|
|
expect(html).toContain('role="alert"')
|
|
})
|
|
|
|
it('should have role="status" for success type', () => {
|
|
const html = flasherTheme.render(createEnvelope({ type: 'success' }))
|
|
|
|
expect(html).toContain('role="status"')
|
|
})
|
|
|
|
it('should have role="status" for info type', () => {
|
|
const html = flasherTheme.render(createEnvelope({ type: 'info' }))
|
|
|
|
expect(html).toContain('role="status"')
|
|
})
|
|
|
|
it('should have aria-live="assertive" for error/warning', () => {
|
|
const errorHtml = flasherTheme.render(createEnvelope({ type: 'error' }))
|
|
const warningHtml = flasherTheme.render(createEnvelope({ type: 'warning' }))
|
|
|
|
expect(errorHtml).toContain('aria-live="assertive"')
|
|
expect(warningHtml).toContain('aria-live="assertive"')
|
|
})
|
|
|
|
it('should have aria-live="polite" for success/info', () => {
|
|
const successHtml = flasherTheme.render(createEnvelope({ type: 'success' }))
|
|
const infoHtml = flasherTheme.render(createEnvelope({ type: 'info' }))
|
|
|
|
expect(successHtml).toContain('aria-live="polite"')
|
|
expect(infoHtml).toContain('aria-live="polite"')
|
|
})
|
|
|
|
it('should have aria-atomic="true"', () => {
|
|
const html = flasherTheme.render(createEnvelope())
|
|
|
|
expect(html).toContain('aria-atomic="true"')
|
|
})
|
|
|
|
it('should have accessible close button label', () => {
|
|
const html = flasherTheme.render(createEnvelope({ type: 'success' }))
|
|
|
|
expect(html).toContain('aria-label="Close success message"')
|
|
})
|
|
})
|
|
|
|
describe('HTML structure', () => {
|
|
it('should have content wrapper', () => {
|
|
const html = flasherTheme.render(createEnvelope())
|
|
|
|
expect(html).toContain('fl-content')
|
|
})
|
|
|
|
it('should have title element with fl-title class', () => {
|
|
const html = flasherTheme.render(createEnvelope())
|
|
|
|
expect(html).toContain('fl-title')
|
|
expect(html).toContain('<strong')
|
|
})
|
|
|
|
it('should have message element with fl-message class', () => {
|
|
const html = flasherTheme.render(createEnvelope())
|
|
|
|
expect(html).toContain('fl-message')
|
|
expect(html).toContain('<span')
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Theme contract', () => {
|
|
it('flasherTheme should have required render function', () => {
|
|
expect(typeof flasherTheme.render).toBe('function')
|
|
})
|
|
|
|
it('render should return string', () => {
|
|
const result = flasherTheme.render(createEnvelope())
|
|
expect(typeof result).toBe('string')
|
|
})
|
|
|
|
it('should handle all standard notification types', () => {
|
|
const types = ['success', 'error', 'warning', 'info']
|
|
|
|
types.forEach((type) => {
|
|
expect(() => flasherTheme.render(createEnvelope({ type }))).not.toThrow()
|
|
})
|
|
})
|
|
|
|
it('should handle custom notification types', () => {
|
|
expect(() => flasherTheme.render(createEnvelope({ type: 'custom' }))).not.toThrow()
|
|
})
|
|
|
|
it('should handle empty message', () => {
|
|
expect(() => flasherTheme.render(createEnvelope({ message: '' }))).not.toThrow()
|
|
})
|
|
|
|
it('should handle empty title', () => {
|
|
expect(() => flasherTheme.render(createEnvelope({ title: '' }))).not.toThrow()
|
|
})
|
|
|
|
it('should handle special characters in message', () => {
|
|
const html = flasherTheme.render(createEnvelope({
|
|
message: 'Test <script>alert("xss")</script>',
|
|
}))
|
|
|
|
// Theme doesn't escape - that's FlasherPlugin's responsibility
|
|
expect(html).toContain('Test <script>alert("xss")</script>')
|
|
})
|
|
})
|