ErrorMatcher.test.tsx101 lines · main
| 1 | import { render, screen } from '@testing-library/react' |
| 2 | import { beforeEach, describe, expect, it, vi } from 'vitest' |
| 3 | |
| 4 | import { ErrorMatcher } from './ErrorMatcher' |
| 5 | import { ConnectionTimeoutError } from '@/types/api-errors' |
| 6 | import { ResponseError } from '@/types/base' |
| 7 | |
| 8 | vi.mock('@/lib/telemetry/track', () => ({ useTrack: () => vi.fn() })) |
| 9 | vi.mock('@/state/ai-assistant-state', () => ({ |
| 10 | useAiAssistantStateSnapshot: () => ({ newChat: vi.fn() }), |
| 11 | })) |
| 12 | vi.mock('@/state/sidebar-manager-state', () => ({ |
| 13 | useSidebarManagerSnapshot: () => ({ openSidebar: vi.fn() }), |
| 14 | })) |
| 15 | vi.mock('@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider', () => ({ |
| 16 | SIDEBAR_KEYS: { AI_ASSISTANT: 'ai-assistant' }, |
| 17 | })) |
| 18 | vi.mock('./RestartProjectDialog', () => ({ |
| 19 | RestartProjectDialog: () => null, |
| 20 | })) |
| 21 | |
| 22 | describe('ErrorMatcher', () => { |
| 23 | beforeEach(() => vi.clearAllMocks()) |
| 24 | |
| 25 | it('renders the provided title and error message', () => { |
| 26 | render( |
| 27 | <ErrorMatcher |
| 28 | title="Failed to load tables" |
| 29 | error="ERROR: FAILED TO RUN SQL QUERY: CONNECTION TERMINATED DUE TO CONNECTION TIMEOUT." |
| 30 | supportFormParams={{}} |
| 31 | /> |
| 32 | ) |
| 33 | expect(screen.getByText('Failed to load tables')).toBeInTheDocument() |
| 34 | expect( |
| 35 | screen.getByText( |
| 36 | 'ERROR: FAILED TO RUN SQL QUERY: CONNECTION TERMINATED DUE TO CONNECTION TIMEOUT.' |
| 37 | ) |
| 38 | ).toBeInTheDocument() |
| 39 | }) |
| 40 | |
| 41 | it('renders troubleshooting steps for classified errors', () => { |
| 42 | const error = new ConnectionTimeoutError('CONNECTION TERMINATED DUE TO CONNECTION TIMEOUT') |
| 43 | render(<ErrorMatcher title="Failed to load tables" error={error} supportFormParams={{}} />) |
| 44 | expect(screen.getByText('Try restarting your project')).toBeInTheDocument() |
| 45 | expect(screen.getByText('Try our troubleshooting guide')).toBeInTheDocument() |
| 46 | expect(screen.getByText('Debug with AI')).toBeInTheDocument() |
| 47 | }) |
| 48 | |
| 49 | it('renders fallback for plain ResponseError (not a classified subclass)', () => { |
| 50 | render( |
| 51 | <ErrorMatcher |
| 52 | title="Failed to load tables" |
| 53 | error={new ResponseError('CONNECTION TERMINATED DUE TO CONNECTION TIMEOUT')} |
| 54 | supportFormParams={{}} |
| 55 | /> |
| 56 | ) |
| 57 | expect(screen.getByText('Failed to load tables')).toBeInTheDocument() |
| 58 | expect(screen.queryByText('Try restarting your project')).not.toBeInTheDocument() |
| 59 | }) |
| 60 | |
| 61 | it('renders fallback with provided title for unmatched errors', () => { |
| 62 | render( |
| 63 | <ErrorMatcher title="Failed to load tables" error="UNKNOWN ERROR" supportFormParams={{}} /> |
| 64 | ) |
| 65 | expect(screen.getByText('Failed to load tables')).toBeInTheDocument() |
| 66 | expect(screen.getByText('UNKNOWN ERROR')).toBeInTheDocument() |
| 67 | }) |
| 68 | |
| 69 | it('accepts error as object with message property', () => { |
| 70 | render( |
| 71 | <ErrorMatcher |
| 72 | title="Failed to load tables" |
| 73 | error={{ message: 'UNKNOWN ERROR' }} |
| 74 | supportFormParams={{}} |
| 75 | /> |
| 76 | ) |
| 77 | expect(screen.getByText('UNKNOWN ERROR')).toBeInTheDocument() |
| 78 | }) |
| 79 | |
| 80 | it('builds support link with projectRef param', () => { |
| 81 | render( |
| 82 | <ErrorMatcher |
| 83 | title="Failed to load tables" |
| 84 | error="UNKNOWN ERROR" |
| 85 | supportFormParams={{ projectRef: 'my-project' }} |
| 86 | /> |
| 87 | ) |
| 88 | expect(screen.getByRole('link', { name: /contact support/i })).toHaveAttribute( |
| 89 | 'href', |
| 90 | '/support/new?projectRef=my-project' |
| 91 | ) |
| 92 | }) |
| 93 | |
| 94 | it('builds support link with no params when supportFormParams is omitted', () => { |
| 95 | render(<ErrorMatcher title="Failed to load tables" error="UNKNOWN ERROR" />) |
| 96 | expect(screen.getByRole('link', { name: /contact support/i })).toHaveAttribute( |
| 97 | 'href', |
| 98 | '/support/new' |
| 99 | ) |
| 100 | }) |
| 101 | }) |