diff --git a/frontend/src/__tests__/ReportIssue.test.jsx b/frontend/src/__tests__/ReportIssue.test.jsx new file mode 100644 index 0000000..0e368c8 --- /dev/null +++ b/frontend/src/__tests__/ReportIssue.test.jsx @@ -0,0 +1,40 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { render, screen, fireEvent } from '@testing-library/react'; +import ReportIssue from '../components/ReportIssue'; + +// Regression guard: the report widget used to ignore resp.ok and always show a +// success checkmark — so a failed POST (4xx/5xx) silently dropped the report. + +describe('ReportIssue', () => { + beforeEach(() => { + global.fetch = vi.fn(); + }); + afterEach(() => { + vi.restoreAllMocks(); + }); + + function openAndSend(text) { + fireEvent.click(screen.getByTitle('Report an issue')); + fireEvent.change(screen.getByPlaceholderText(/Describe what happened/i), { + target: { value: text }, + }); + fireEvent.click(screen.getByRole('button', { name: /Send Report/i })); + } + + it('shows a failure message (NOT success) when the backend POST fails', async () => { + global.fetch.mockResolvedValue({ ok: false }); + render(); + openAndSend('Inventory page is blank'); + + expect(await screen.findByText(/Couldn't send your report/i)).toBeInTheDocument(); + expect(screen.queryByText(/We'll look into it/i)).not.toBeInTheDocument(); + }); + + it('shows success when the report actually sends', async () => { + global.fetch.mockResolvedValue({ ok: true }); + render(); + openAndSend('Just a note'); + + expect(await screen.findByText(/We'll look into it/i)).toBeInTheDocument(); + }); +}); diff --git a/frontend/src/components/ReportIssue.jsx b/frontend/src/components/ReportIssue.jsx index fa6f39e..bc9e87c 100644 --- a/frontend/src/components/ReportIssue.jsx +++ b/frontend/src/components/ReportIssue.jsx @@ -10,6 +10,7 @@ export default function ReportIssue() { const [description, setDescription] = useState(''); const [sent, setSent] = useState(false); const [sending, setSending] = useState(false); + const [failed, setFailed] = useState(false); const submit = async () => { if (!description.trim()) return; @@ -24,21 +25,27 @@ export default function ReportIssue() { timestamp: new Date().toISOString(), }; + let ok = false; try { - // Try to send to backend (which will log + optionally notify) - await fetch('/api/feedback', { + const resp = await fetch('/api/feedback', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(report), }); + ok = resp.ok; // a 4xx/5xx is NOT a successful submission } catch { - // Even if backend fails, log locally - console.log('Issue report:', report); + ok = false; } setSending(false); - setSent(true); - setTimeout(() => { setSent(false); setOpen(false); setDescription(''); }, 2000); + if (ok) { + setSent(true); + setTimeout(() => { setSent(false); setOpen(false); setDescription(''); }, 2000); + } else { + // Don't falsely confirm — let the customer retry or call instead. + console.warn('Issue report failed to send:', report); + setFailed(true); + } }; if (!open) { @@ -69,6 +76,17 @@ export default function ReportIssue() { Thank you! We'll look into it. + ) : failed ? ( +
+

Couldn't send your report.

+

Please try again, or call our showroom and we'll help right away.

+ +
) : ( <>