-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Render okta errors based on error param (#3196)
- Loading branch information
1 parent
1f8f915
commit 8749dcc
Showing
8 changed files
with
270 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
src/shared/GlobalTopBanners/OktaErrorBanners/OktaErrorBanners.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import * as Sentry from '@sentry/react' | ||
import { render, screen } from '@testing-library/react' | ||
import { MemoryRouter, Route } from 'react-router-dom' | ||
|
||
import OktaErrorBanners from './OktaErrorBanners' | ||
|
||
jest.mock('@sentry/react', () => { | ||
const originalModule = jest.requireActual('@sentry/react') | ||
return { | ||
...originalModule, | ||
captureMessage: jest.fn(), | ||
} | ||
}) | ||
|
||
const wrapper = | ||
( | ||
initialEntries = ['/gh/codecov'], | ||
path = '/:provider/:owner' | ||
): React.FC<React.PropsWithChildren> => | ||
({ children }) => ( | ||
<MemoryRouter initialEntries={initialEntries}> | ||
<Route path={path}>{children}</Route> | ||
</MemoryRouter> | ||
) | ||
|
||
describe('OktaErrorBanners', () => { | ||
it('should return null if owner is not provided', () => { | ||
const { container } = render(<OktaErrorBanners />, { | ||
wrapper: wrapper(['/gh/'], '/:provider'), | ||
}) | ||
|
||
expect(container).toBeEmptyDOMElement() | ||
}) | ||
|
||
it('should return null if error is not provided', () => { | ||
const { container } = render(<OktaErrorBanners />, { | ||
wrapper: wrapper(['/gh/codecov']), | ||
}) | ||
|
||
expect(container).toBeEmptyDOMElement() | ||
}) | ||
|
||
it('should render error message for invalid_request', () => { | ||
render(<OktaErrorBanners />, { | ||
wrapper: wrapper(['/gh/codecov?error=invalid_request']), | ||
}) | ||
|
||
const content = screen.getByText( | ||
/Invalid request: The request parameters aren't valid. Please try again or contact support./ | ||
) | ||
expect(content).toBeInTheDocument() | ||
}) | ||
|
||
it('should render error message for unauthorized_client', () => { | ||
render(<OktaErrorBanners />, { | ||
wrapper: wrapper(['/gh/codecov?error=unauthorized_client']), | ||
}) | ||
|
||
const content = screen.getByText( | ||
/Unauthorized client: The client isn't authorized to request an authorization code using this method. Please reach out to your administrator./ | ||
) | ||
expect(content).toBeInTheDocument() | ||
}) | ||
|
||
it('should render error message for access_denied', () => { | ||
render(<OktaErrorBanners />, { | ||
wrapper: wrapper(['/gh/codecov?error=access_denied']), | ||
}) | ||
|
||
const content = screen.getByText( | ||
/The resource owner or authorization server denied the request/ | ||
) | ||
expect(content).toBeInTheDocument() | ||
}) | ||
|
||
it('should render default error message for unknown error', () => { | ||
render(<OktaErrorBanners />, { | ||
wrapper: wrapper(['/gh/codecov?error=unknown']), | ||
}) | ||
|
||
const content = screen.getByText( | ||
/An unknown error occurred. Please try again or contact support./ | ||
) | ||
expect(content).toBeInTheDocument() | ||
}) | ||
|
||
it('should capture unknown error message', () => { | ||
render(<OktaErrorBanners />, { | ||
wrapper: wrapper(['/gh/codecov?error=unknown']), | ||
}) | ||
|
||
expect(Sentry.captureMessage).toHaveBeenCalledWith( | ||
'Unknown Okta error: unknown', | ||
{ | ||
fingerprint: ['unknown-okta-error'], | ||
tags: { | ||
error: 'unknown', | ||
}, | ||
} | ||
) | ||
}) | ||
|
||
it('should render dismiss button', () => { | ||
render(<OktaErrorBanners />, { | ||
wrapper: wrapper(['/gh/codecov?error=invalid_request']), | ||
}) | ||
|
||
const dismissButton = screen.getByRole('button', { name: /Dismiss/ }) | ||
expect(dismissButton).toBeInTheDocument() | ||
}) | ||
}) |
41 changes: 41 additions & 0 deletions
41
src/shared/GlobalTopBanners/OktaErrorBanners/OktaErrorBanners.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { useLocation, useParams } from 'react-router-dom' | ||
|
||
import Icon from 'ui/Icon' | ||
import TopBanner from 'ui/TopBanner' | ||
|
||
import { getOktaErrorMessage } from './enums' | ||
|
||
interface URLParams { | ||
owner?: string | ||
} | ||
|
||
const OktaErrorBanners = () => { | ||
const { owner } = useParams<URLParams>() | ||
const location = useLocation() | ||
|
||
const searchParams = new URLSearchParams(location.search) | ||
const error = searchParams.get('error') | ||
|
||
if (!owner || !error) return null | ||
|
||
const errorMessage = getOktaErrorMessage(error) | ||
|
||
return ( | ||
<TopBanner variant="error"> | ||
<TopBanner.Start> | ||
<p className="items-center gap-1 md:flex"> | ||
<span className="flex items-center gap-1 font-semibold"> | ||
<Icon name="exclamationCircle" /> | ||
Okta Authentication Error | ||
</span> | ||
{errorMessage} | ||
</p> | ||
</TopBanner.Start> | ||
<TopBanner.End> | ||
<TopBanner.DismissButton>Dismiss</TopBanner.DismissButton> | ||
</TopBanner.End> | ||
</TopBanner> | ||
) | ||
} | ||
|
||
export default OktaErrorBanners |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import * as Sentry from '@sentry/react' | ||
|
||
const ErrorType = { | ||
UnauthorizedClient: 'unauthorized_client', | ||
AccessDenied: 'access_denied', | ||
UnsupportedResponseType: 'unsupported_response_type', | ||
UnsupportedResponseMode: 'unsupported_response_mode', | ||
InvalidScope: 'invalid_scope', | ||
ServerError: 'server_error', | ||
TemporarilyUnavailable: 'temporarily_unavailable', | ||
InvalidClient: 'invalid_client', | ||
LoginRequired: 'login_required', | ||
InvalidRequest: 'invalid_request', | ||
UserCanceledRequest: 'user_canceled_request', | ||
} as const | ||
|
||
const errorMessages = { | ||
[ErrorType.UnauthorizedClient]: | ||
"Unauthorized client: The client isn't authorized to request an authorization code using this method. Please reach out to your administrator.", | ||
[ErrorType.AccessDenied]: | ||
'Access denied: The resource owner or authorization server denied the request. Please reach out to your administrator.', | ||
[ErrorType.UnsupportedResponseType]: | ||
"Unsupported response type: The authorization server doesn't support obtaining an authorization code using this method. Please reach out to your administrator.", | ||
[ErrorType.UnsupportedResponseMode]: | ||
"Unsupported response mode: The authorization server doesn't support the requested response mode. Please reach out to your administrator.", | ||
[ErrorType.InvalidScope]: | ||
'Invalid scope: The requested scope is invalid, unknown, or malformed. Please reach out to your administrator.', | ||
[ErrorType.ServerError]: | ||
'Server error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. Please try again later or contact support.', | ||
[ErrorType.TemporarilyUnavailable]: | ||
'Temporarily unavailable: The authorization server is currently unable to handle the request due to temporary overloading or maintenance. Please try again later.', | ||
[ErrorType.InvalidClient]: | ||
"Invalid client: The specified client isn't valid. Please reach out to your administrator.", | ||
[ErrorType.LoginRequired]: | ||
"Login required: The client specified not to prompt, but the user isn't signed in. Please sign in and try again.", | ||
[ErrorType.InvalidRequest]: | ||
"Invalid request: The request parameters aren't valid. Please try again or contact support.", | ||
[ErrorType.UserCanceledRequest]: | ||
'Request canceled: User canceled the social sign-in request. Please try again if this was unintentional.', | ||
} as const | ||
|
||
export const getOktaErrorMessage = (error: string): string => { | ||
if (error in errorMessages) { | ||
return errorMessages[error as keyof typeof errorMessages] | ||
} | ||
|
||
Sentry.captureMessage(`Unknown Okta error: ${error}`, { | ||
fingerprint: ['unknown-okta-error'], | ||
tags: { | ||
error: error, | ||
}, | ||
}) | ||
|
||
return 'An unknown error occurred. Please try again or contact support.' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from './OktaErrorBanners' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters