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.
+
+
) : (
<>