Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "webapp",
"version": "2.28.0",
"version": "2.28.1",
"private": true,
"scripts": {
"dev": "next dev",
Expand Down
28 changes: 28 additions & 0 deletions src/app/api/sentry-test/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as Sentry from '@sentry/node';

import { serverEnv } from '@/lib/env/server';

export const POST = async (): Promise<Response> => {
const testError = new Error(
`[Sentry Test] Server error at ${new Date().toISOString()}`,
);
testError.name = 'SentryServerTestError';

if (!serverEnv.SENTRY_DSN) {
return Response.json({
status: 'no_dsn',
message: 'SENTRY_DSN is not set. Errors would only go to console.error.',
});
}

Sentry.captureException(testError);

// Flush to ensure the event is sent before the response completes
await Sentry.flush(2000);

return Response.json({
status: 'sent',
message: 'Error captured and flushed to Sentry. Check your dashboard.',
dsn_host: new URL(serverEnv.SENTRY_DSN).hostname,
});
};
5 changes: 5 additions & 0 deletions src/app/sentry-test/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { TriggerError } from './trigger-error';

export default function SentryTestPage() {
return <TriggerError />;
}
112 changes: 112 additions & 0 deletions src/app/sentry-test/trigger-error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
'use client';

import { useState } from 'react';

import { reportError } from '@/features/error-reporter/reporter';

export const TriggerError = () => {
const [status, setStatus] = useState<string>('');

const triggerClientReportedError = () => {
setStatus(
'Sending client error via reportError() → /api/error → Sentry...',
);
const error = new Error(
`[Sentry Test] Client error at ${new Date().toISOString()}`,
);
error.name = 'SentryTestError';
reportError(error);
setStatus(
'Client error sent via sendBeacon. Check /api/error logs and Sentry dashboard.',
);
};

const triggerUnhandledError = () => {
setStatus('Throwing unhandled error (caught by GlobalErrorSetup)...');
setTimeout(() => {
throw new Error(
`[Sentry Test] Unhandled error at ${new Date().toISOString()}`,
);
}, 100);
};

const triggerUnhandledRejection = () => {
setStatus('Triggering unhandled promise rejection...');
Promise.reject(
new Error(
`[Sentry Test] Unhandled rejection at ${new Date().toISOString()}`,
),
);
};

const triggerServerError = async () => {
setStatus('Calling /api/sentry-test to trigger server-side error...');
try {
const res = await fetch('/api/sentry-test', { method: 'POST' });
const data = await res.json();
setStatus(`Server response: ${JSON.stringify(data)}`);
} catch (e) {
setStatus(`Fetch failed: ${e instanceof Error ? e.message : String(e)}`);
}
};

return (
<div className='mx-auto max-w-xl space-y-6 p-8'>
<h1 className='text-2xl font-bold'>Sentry Test Page</h1>
<p className='text-sm text-muted-foreground'>
Use these buttons to trigger errors and verify they appear in Sentry and
Slack.
</p>

<div className='space-y-3'>
<button
type='button'
onClick={triggerClientReportedError}
className='w-full rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-700'
>
1. Client Error (via reportError → /api/error)
</button>

<button
type='button'
onClick={triggerUnhandledError}
className='w-full rounded bg-orange-600 px-4 py-2 text-white hover:bg-orange-700'
>
2. Unhandled Error (window.error → GlobalErrorSetup)
</button>

<button
type='button'
onClick={triggerUnhandledRejection}
className='w-full rounded bg-yellow-600 px-4 py-2 text-white hover:bg-yellow-700'
>
3. Unhandled Promise Rejection
</button>

<button
type='button'
onClick={triggerServerError}
className='w-full rounded bg-red-600 px-4 py-2 text-white hover:bg-red-700'
>
4. Server-side Error (direct Sentry.captureException)
</button>
</div>

{status && (
<pre className='overflow-auto rounded bg-muted p-3 text-xs whitespace-pre-wrap'>
{status}
</pre>
)}

<div className='border-t pt-4 text-xs text-gray-500'>
<p className='font-semibold'>What to check after clicking:</p>
<ul className='mt-1 list-inside list-disc space-y-1'>
<li>Sentry Dashboard → jobstash/webapp → Issues</li>
<li>Slack channel linked to Sentry alerts</li>
<li>Server logs for &quot;[ErrorReporter]&quot; or Sentry errors</li>
<li>Browser DevTools → Network tab → /api/error requests</li>
</ul>
</div>
</div>
);
};
Loading