-
Notifications
You must be signed in to change notification settings - Fork 147
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Integ 231 improve error handling within analytics app component (#2919)
* Fix overflow of error messages in Note component * Adjust empty data message * Add HyperLink component with tests * Adjust tests in SlugWarningDisplay component * Add ErrorDisplay component and adjust error types * Lint fixes * Remove console * Some copy changes * Add spec to ErrorDisplay * Fix linter * Fix typing of HyperLink component * Small semantic changes * Cleaned-up variables declarations * Handle errors other than explicit API types and fix width of note banner * Change variable name * Update copies * adjust copies and add hyperlinks to contact support * Refactor to avoid JSX elements in state as per PR review * Add handling for other errors * Remove console.error * Set error to null when successfully retreiving data
- Loading branch information
Showing
15 changed files
with
376 additions
and
64 deletions.
There are no files selected for viewing
27 changes: 27 additions & 0 deletions
27
apps/google-analytics-4/frontend/src/components/common/HyperLink/HyperLink.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,27 @@ | ||
import HyperLink from './HyperLink'; | ||
import { render, screen } from '@testing-library/react'; | ||
|
||
const BODY = 'Have a great day!'; | ||
const SUBSTRING = 'great'; | ||
|
||
const { getByTestId } = screen; | ||
|
||
describe('HyperLink component', () => { | ||
it('can render the TextLink component in place of substring value', () => { | ||
render(<HyperLink body={BODY} substring={SUBSTRING} />); | ||
|
||
const textLink = getByTestId('cf-ui-text-link'); | ||
|
||
expect(textLink).toBeVisible(); | ||
expect(textLink.firstChild).toHaveTextContent(SUBSTRING); | ||
}); | ||
|
||
it('can handle onClick of link', () => { | ||
const mockOnClick = jest.fn(); | ||
render(<HyperLink body={BODY} substring={SUBSTRING} onClick={mockOnClick} />); | ||
|
||
const textLink = getByTestId('cf-ui-text-link'); | ||
textLink.click(); | ||
expect(mockOnClick).toHaveBeenCalled(); | ||
}); | ||
}); |
32 changes: 32 additions & 0 deletions
32
apps/google-analytics-4/frontend/src/components/common/HyperLink/HyperLink.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,32 @@ | ||
import React, { MouseEventHandler } from 'react'; | ||
import { TextLink } from '@contentful/f36-components'; | ||
|
||
interface Props { | ||
body: string; | ||
substring: string; | ||
onClick?: MouseEventHandler<HTMLAnchorElement>; | ||
hyperLinkHref?: string; | ||
} | ||
|
||
const HyperLink = (props: Props) => { | ||
const { body, substring, onClick = () => {}, hyperLinkHref } = props; | ||
const link = ( | ||
<TextLink onClick={onClick} href={hyperLinkHref} target="_blank" rel="noopener noreferer"> | ||
{substring} | ||
</TextLink> | ||
); | ||
|
||
const formatLink = () => { | ||
const bodyWithTextLink = body.split(substring).reduce((prev: any, current, i) => { | ||
if (!i) { | ||
return [current]; | ||
} | ||
return prev.concat(link, current); | ||
}, []); | ||
return bodyWithTextLink as JSX.Element; | ||
}; | ||
|
||
return formatLink(); | ||
}; | ||
|
||
export default HyperLink; |
4 changes: 2 additions & 2 deletions
4
apps/google-analytics-4/frontend/src/components/common/Note/Note.styles.ts
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
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
5 changes: 5 additions & 0 deletions
5
apps/google-analytics-4/frontend/src/components/main-app/ChartContent/ChartContent.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
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
9 changes: 9 additions & 0 deletions
9
apps/google-analytics-4/frontend/src/components/main-app/ChartHeader/ChartHeader.styles.ts
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,9 @@ | ||
import { css } from 'emotion'; | ||
import tokens from '@contentful/f36-tokens'; | ||
|
||
export const styles = { | ||
root: css({ | ||
marginTop: tokens.spacing2Xs, | ||
marginRight: tokens.spacing2Xs, | ||
}), | ||
}; |
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
24 changes: 24 additions & 0 deletions
24
.../google-analytics-4/frontend/src/components/main-app/ErrorDisplay/CommonErrorDisplays.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,24 @@ | ||
import React from 'react'; | ||
import { useSDK } from '@contentful/react-apps-toolkit'; | ||
import { SidebarExtensionSDK } from '@contentful/app-sdk'; | ||
import { DEFAULT_ERR_MSG } from 'components/main-app/constants/noteMessages'; | ||
import HyperLink from 'components/common/HyperLink/HyperLink'; | ||
|
||
interface AppConfigPageHyperLinkProps { | ||
bodyMsg: string; | ||
} | ||
|
||
export const AppConfigPageHyperLink = (props: AppConfigPageHyperLinkProps) => { | ||
const { bodyMsg } = props; | ||
const sdk = useSDK<SidebarExtensionSDK>(); | ||
const openConfigPage = () => sdk.navigator.openAppConfig(); | ||
return <HyperLink body={bodyMsg} substring="app configuration page." onClick={openConfigPage} />; | ||
}; | ||
|
||
export const SupportHyperLink = () => ( | ||
<HyperLink | ||
body={DEFAULT_ERR_MSG} | ||
substring="contact support." | ||
hyperLinkHref="https://www.contentful.com/support/?utm_source=webapp&utm_medium=help-menu&utm_campaign=in-app-help" | ||
/> | ||
); |
134 changes: 134 additions & 0 deletions
134
apps/google-analytics-4/frontend/src/components/main-app/ErrorDisplay/ErrorDisplay.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,134 @@ | ||
import ErrorDisplay from './ErrorDisplay'; | ||
import { render, screen } from '@testing-library/react'; | ||
import { mockSdk } from '../../../../test/mocks'; | ||
import { | ||
DEFAULT_ERR_MSG, | ||
INVALID_ARGUMENT_MSG, | ||
INVALID_SERVICE_ACCOUNT, | ||
PERMISSION_DENIED_MSG, | ||
} from '../constants/noteMessages'; | ||
import { ApiError } from 'apis/api'; | ||
|
||
jest.mock('@contentful/react-apps-toolkit', () => ({ | ||
useSDK: () => mockSdk, | ||
})); | ||
|
||
const { findByText, getByTestId } = screen; | ||
|
||
describe('ErrorDisplay', () => { | ||
it('mounts with correct msg and hyperlink when error is of type InvalidProperty', async () => { | ||
const HYPER_LINK_COPY = 'app configuration page.'; | ||
render( | ||
<ErrorDisplay | ||
error={ | ||
new ApiError({ | ||
details: '', | ||
message: '', | ||
status: 404, | ||
errorType: 'InvalidProperty', | ||
}) | ||
} | ||
/> | ||
); | ||
|
||
const warningMsg = await findByText(INVALID_ARGUMENT_MSG.replace(HYPER_LINK_COPY, '').trim()); | ||
const hyperLink = getByTestId('cf-ui-text-link'); | ||
|
||
expect(warningMsg).toBeVisible(); | ||
expect(hyperLink).toBeVisible(); | ||
}); | ||
|
||
it('mounts with correct msg when error is of type DisabledDataApi', async () => { | ||
render( | ||
<ErrorDisplay | ||
error={ | ||
new ApiError({ | ||
details: '', | ||
message: '', | ||
status: 404, | ||
errorType: 'DisabledDataApi', | ||
}) | ||
} | ||
/> | ||
); | ||
|
||
const warningMsg = await findByText(PERMISSION_DENIED_MSG); | ||
|
||
expect(warningMsg).toBeVisible(); | ||
}); | ||
|
||
it('mounts with correct msg when error is of type FailedFetch', async () => { | ||
const HYPER_LINK_COPY = 'contact support.'; | ||
render( | ||
<ErrorDisplay | ||
error={ | ||
new ApiError({ | ||
details: '', | ||
message: '', | ||
status: 404, | ||
errorType: 'FailedFetch', | ||
}) | ||
} | ||
/> | ||
); | ||
|
||
const warningMsg = await findByText(DEFAULT_ERR_MSG.replace(HYPER_LINK_COPY, '').trim()); | ||
const hyperLink = getByTestId('cf-ui-text-link'); | ||
|
||
expect(warningMsg).toBeVisible(); | ||
expect(hyperLink).toBeVisible(); | ||
}); | ||
|
||
it('mounts with correct msg when error is of type InvalidServiceAccount', async () => { | ||
const HYPER_LINK_COPY = 'app configuration page.'; | ||
render( | ||
<ErrorDisplay | ||
error={ | ||
new ApiError({ | ||
details: '', | ||
message: '', | ||
status: 404, | ||
errorType: 'InvalidServiceAccount', | ||
}) | ||
} | ||
/> | ||
); | ||
|
||
const warningMsg = await findByText( | ||
INVALID_SERVICE_ACCOUNT.replace(HYPER_LINK_COPY, '').trim() | ||
); | ||
const hyperLink = getByTestId('cf-ui-text-link'); | ||
|
||
expect(warningMsg).toBeVisible(); | ||
expect(hyperLink).toBeVisible(); | ||
}); | ||
|
||
it('mounts with correct msg when error is of ApiError class but not an Error type explicitely handled', async () => { | ||
const INTERNAL_ERR_MSG = 'Internal Server Error'; | ||
render( | ||
<ErrorDisplay | ||
error={ | ||
new ApiError({ | ||
details: '', | ||
message: INTERNAL_ERR_MSG, | ||
status: 500, | ||
errorType: '', | ||
}) | ||
} | ||
/> | ||
); | ||
|
||
const warningMsg = await findByText(INTERNAL_ERR_MSG); | ||
|
||
expect(warningMsg).toBeVisible(); | ||
}); | ||
|
||
it('mounts with correct msg when error is not a specified Api Error Type ', async () => { | ||
const ERR_MSG = 'random error'; | ||
render(<ErrorDisplay error={new Error(ERR_MSG)} />); | ||
|
||
const warningMsg = await findByText(ERR_MSG); | ||
|
||
expect(warningMsg).toBeVisible(); | ||
}); | ||
}); |
Oops, something went wrong.