Skip to content

Commit d3f2342

Browse files
authored
Merge branch 'main' into feat/addedrepoName
2 parents 710470b + fa0f1b7 commit d3f2342

File tree

29 files changed

+1859
-161
lines changed

29 files changed

+1859
-161
lines changed

frontend/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,6 @@ node_modules/
4646
/playwright-report/
4747
/blob-report/
4848
/playwright/.cache/
49+
50+
# Sentry Config File
51+
.env.sentry-build-plugin

frontend/__tests__/unit/pages/Contribute.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ describe('Contribute Component', () => {
110110

111111
test('handles pagination for first page', async () => {
112112
;(fetchAlgoliaData as jest.Mock).mockResolvedValue({
113-
...mockContributeData,
113+
hits: mockContributeData.issues,
114114
totalPages: 2,
115115
currentPage: 1,
116116
})

frontend/__tests__/unit/pages/OrganizationDetails.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ describe('OrganizationDetailsPage', () => {
141141
await waitFor(() => {
142142
expect(screen.getByText('Organization not found')).toBeInTheDocument()
143143
expect(addToast).toHaveBeenCalledWith({
144-
description: 'Unable to complete the requested operation.',
145-
title: 'GraphQL Request Failed',
146-
timeout: 3000,
144+
description: 'An unexpected server error occurred.',
145+
title: 'Server Error',
146+
timeout: 5000,
147147
shouldShowTimeoutProgress: true,
148148
color: 'danger',
149149
variant: 'solid',

frontend/__tests__/unit/pages/ProjectDetails.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ describe('ProjectDetailsPage', () => {
8787
await waitFor(() => screen.getByText('Project not found'))
8888
expect(screen.getByText('Project not found')).toBeInTheDocument()
8989
expect(addToast).toHaveBeenCalledWith({
90-
description: 'Unable to complete the requested operation.',
91-
title: 'GraphQL Request Failed',
92-
timeout: 3000,
90+
description: 'An unexpected server error occurred.',
91+
title: 'Server Error',
92+
timeout: 5000,
9393
shouldShowTimeoutProgress: true,
9494
color: 'danger',
9595
variant: 'solid',

frontend/__tests__/unit/pages/RepositoryDetails.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ describe('RepositoryDetailsPage', () => {
8989
await waitFor(() => screen.getByText('Repository not found'))
9090
expect(screen.getByText('Repository not found')).toBeInTheDocument()
9191
expect(addToast).toHaveBeenCalledWith({
92-
description: 'Unable to complete the requested operation.',
93-
title: 'GraphQL Request Failed',
94-
timeout: 3000,
92+
description: 'An unexpected server error occurred.',
93+
title: 'Server Error',
94+
timeout: 5000,
9595
shouldShowTimeoutProgress: true,
9696
color: 'danger',
9797
variant: 'solid',

frontend/__tests__/unit/pages/SnapshotDetails.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ describe('SnapshotDetailsPage', () => {
9090
await waitFor(() => screen.getByText('Snapshot not found'))
9191
expect(screen.getByText('Snapshot not found')).toBeInTheDocument()
9292
expect(addToast).toHaveBeenCalledWith({
93-
description: 'Unable to complete the requested operation.',
94-
title: 'GraphQL Request Failed',
95-
timeout: 3000,
93+
description: 'An unexpected server error occurred.',
94+
title: 'Server Error',
95+
timeout: 5000,
9696
shouldShowTimeoutProgress: true,
9797
color: 'danger',
9898
variant: 'solid',

frontend/__tests__/unit/pages/UserDetails.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,9 @@ describe('UserDetailsPage', () => {
243243
})
244244

245245
expect(addToast).toHaveBeenCalledWith({
246-
description: 'Unable to complete the requested operation.',
247-
title: 'GraphQL Request Failed',
248-
timeout: 3000,
246+
description: 'An unexpected server error occurred.',
247+
title: 'Server Error',
248+
timeout: 5000,
249249
shouldShowTimeoutProgress: true,
250250
color: 'danger',
251251
variant: 'solid',
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { addToast } from '@heroui/toast'
2+
import * as Sentry from '@sentry/nextjs'
3+
import { screen, fireEvent } from '@testing-library/react'
4+
import { useRouter } from 'next/navigation'
5+
import { render } from 'wrappers/testUtil'
6+
import GlobalError, {
7+
AppError,
8+
ERROR_CONFIGS,
9+
ErrorDisplay,
10+
ErrorWrapper,
11+
handleAppError,
12+
} from 'app/global-error'
13+
14+
// Mocks
15+
jest.mock('next/navigation', () => ({
16+
useRouter: jest.fn(),
17+
}))
18+
jest.mock('@sentry/nextjs', () => ({
19+
captureException: jest.fn(),
20+
ErrorBoundary: ({ _fallback, children }) => <>{children}</>,
21+
}))
22+
jest.mock('@heroui/toast', () => ({
23+
addToast: jest.fn(),
24+
}))
25+
26+
describe('ErrorDisplay Component', () => {
27+
test('renders correct error details', () => {
28+
render(<ErrorDisplay statusCode={404} title="Not Found" message="Page not found" />)
29+
30+
expect(screen.getByText('404')).toBeInTheDocument()
31+
expect(screen.getByText('Not Found')).toBeInTheDocument()
32+
expect(screen.getByText('Page not found')).toBeInTheDocument()
33+
})
34+
35+
test('navigates to home on button press', () => {
36+
const pushMock = jest.fn()
37+
;(useRouter as jest.Mock).mockReturnValue({ push: pushMock })
38+
39+
render(<ErrorDisplay {...ERROR_CONFIGS['404']} />)
40+
41+
fireEvent.click(screen.getByText('Return To Home'))
42+
expect(pushMock).toHaveBeenCalledWith('/')
43+
})
44+
})
45+
46+
describe('handleAppError Function', () => {
47+
beforeEach(() => {
48+
jest.clearAllMocks()
49+
})
50+
51+
test('handles AppError without Sentry for 404', () => {
52+
const error = new AppError(404, 'Page not found')
53+
handleAppError(error)
54+
55+
expect(Sentry.captureException).not.toHaveBeenCalled()
56+
expect(addToast).toHaveBeenCalledWith(
57+
expect.objectContaining({
58+
title: 'Page Not Found',
59+
description: 'Page not found',
60+
})
61+
)
62+
})
63+
64+
test('handles unknown error and calls Sentry for 500+', () => {
65+
handleAppError('Unknown crash')
66+
67+
expect(Sentry.captureException).toHaveBeenCalled()
68+
expect(addToast).toHaveBeenCalledWith(
69+
expect.objectContaining({
70+
description: 'An unexpected server error occurred.',
71+
shouldShowTimeoutProgress: true,
72+
timeout: 5000,
73+
title: 'Server Error',
74+
})
75+
)
76+
})
77+
78+
test('handles normal Error instance', () => {
79+
const err = new Error('Oops')
80+
handleAppError(err)
81+
82+
expect(Sentry.captureException).toHaveBeenCalledWith(err)
83+
expect(addToast).toHaveBeenCalledWith(
84+
expect.objectContaining({
85+
description: 'Oops',
86+
})
87+
)
88+
})
89+
})
90+
91+
describe('AppError class', () => {
92+
test('should extend Error properly', () => {
93+
const err = new AppError(403, 'Forbidden')
94+
expect(err).toBeInstanceOf(Error)
95+
expect(err.name).toBe('AppError')
96+
expect(err.message).toBe('Forbidden')
97+
expect(err.statusCode).toBe(403)
98+
})
99+
})
100+
101+
describe('GlobalError component', () => {
102+
test('renders 500 fallback and calls Sentry', () => {
103+
const error = new Error('Critical failure')
104+
render(<GlobalError error={error} />)
105+
106+
expect(Sentry.captureException).toHaveBeenCalledWith(error)
107+
expect(screen.getByText('Server Error')).toBeInTheDocument()
108+
})
109+
})
110+
111+
describe('ErrorWrapper component', () => {
112+
test('renders children without crashing', () => {
113+
render(
114+
<ErrorWrapper>
115+
<div>App Content</div>
116+
</ErrorWrapper>
117+
)
118+
119+
expect(screen.getByText('App Content')).toBeInTheDocument()
120+
})
121+
})

frontend/jest.config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ const config: Config = {
99
'!src/app/layout.tsx',
1010
'!src/components/**',
1111
'!src/hooks/**',
12+
'!src/instrumentation.ts',
13+
'!src/instrumentation-client.ts',
1214
'!src/reportWebVitals.ts',
13-
'!src/sentry.config.ts',
15+
'!src/sentry.server.config.ts',
1416
'!src/server/**',
1517
'!src/setupTests.ts',
1618
'!src/types/**',

frontend/next.config.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import { withSentryConfig } from '@sentry/nextjs'
12
import type { NextConfig } from 'next'
23

34
const isLocal = process.env.NEXT_PUBLIC_ENVIRONMENT === 'local'
45

56
const nextConfig: NextConfig = {
67
images: {
8+
// This is a list of remote patterns that Next.js will use to determine
9+
// if an image is allowed to be loaded from a remote source.
710
remotePatterns: [
811
{
912
protocol: 'https',
@@ -27,4 +30,10 @@ const nextConfig: NextConfig = {
2730
...(isLocal ? {} : { output: 'standalone' }),
2831
}
2932

30-
export default nextConfig
33+
export default withSentryConfig(nextConfig, {
34+
// https://www.npmjs.com/package/@sentry/webpack-plugin#options
35+
org: 'OWASP',
36+
project: 'Nest',
37+
widenClientFileUpload: true,
38+
disableLogger: false,
39+
})

0 commit comments

Comments
 (0)