diff --git a/frontend/src/components/ui/__tests__/sonner.test.tsx b/frontend/src/components/ui/__tests__/sonner.test.tsx new file mode 100644 index 0000000..dc23446 --- /dev/null +++ b/frontend/src/components/ui/__tests__/sonner.test.tsx @@ -0,0 +1,36 @@ +import { describe, it, expect, afterEach, beforeAll, vi } from 'vitest' +import { render, cleanup, waitFor } from '@testing-library/react' +import { toast } from 'sonner' +import { Toaster } from '../sonner' + +beforeAll(() => { + // sonner reads matchMedia for theme detection; jsdom doesn't provide it. + window.matchMedia = vi.fn().mockImplementation((query: string) => ({ + matches: false, + media: query, + onchange: null, + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + addListener: vi.fn(), + removeListener: vi.fn(), + dispatchEvent: vi.fn(), + })) +}) + +afterEach(() => cleanup()) + +describe('Toaster', () => { + it('renders error toasts on a red surface so failures are visible', async () => { + render() + toast.error('Save failed') + // The style (with the CSS vars) lands on the toast list, mounted on first toast. + const list = await waitFor(() => { + const el = document.querySelector('[data-sonner-toaster]') as HTMLElement | null + expect(el).not.toBeNull() + return el! + }) + const style = list.getAttribute('style') ?? '' + expect(style).toContain('--error-bg: #f85149') + expect(style).toContain('--error-text: #ffffff') + }) +}) diff --git a/frontend/src/components/ui/sonner.tsx b/frontend/src/components/ui/sonner.tsx index 9280ee5..12ab15f 100644 --- a/frontend/src/components/ui/sonner.tsx +++ b/frontend/src/components/ui/sonner.tsx @@ -34,6 +34,11 @@ const Toaster = ({ ...props }: ToasterProps) => { "--normal-text": "var(--popover-foreground)", "--normal-border": "var(--border)", "--border-radius": "var(--radius)", + // Errors use a red surface so failures (e.g. a failed save while the + // backend is down) stand out instead of reading like a normal toast. + "--error-bg": "#f85149", + "--error-text": "#ffffff", + "--error-border": "#da3633", } as React.CSSProperties } toastOptions={{