-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: show a modal on failure of getInfo and getComponents
refs: SHELL-92 (#251)
- Loading branch information
1 parent
4bf7746
commit 2df0658
Showing
15 changed files
with
327 additions
and
162 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
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 was deleted.
Oops, something went wrong.
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,82 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2023 Zextras <https://www.zextras.com> | ||
* | ||
* SPDX-License-Identifier: AGPL-3.0-only | ||
*/ | ||
import { rest } from 'msw'; | ||
import { act, screen } from '@testing-library/react'; | ||
import React from 'react'; | ||
import server from '../mocks/server'; | ||
import { GetComponentsJsonResponseBody } from '../mocks/handlers/components'; | ||
import { setup } from '../test/utils'; | ||
import { Loader } from './loader'; | ||
import { LOGIN_V3_CONFIG_PATH } from '../constants'; | ||
|
||
jest.mock('../workers'); | ||
jest.mock('../reporting/functions'); | ||
|
||
describe('Loader', () => { | ||
test('If only getComponents request fails, the LoaderFailureModal appears', async () => { | ||
// using getInfo and loginConfig default handlers | ||
server.use( | ||
rest.get<never, never, Partial<GetComponentsJsonResponseBody>>( | ||
'/static/iris/components.json', | ||
(req, res, ctx) => | ||
res(ctx.status(503, 'Controlled error: fail components.json request'), ctx.json({})) | ||
) | ||
); | ||
|
||
setup(<Loader />); | ||
|
||
const title = await screen.findByText('Something went wrong...'); | ||
act(() => { | ||
jest.runOnlyPendingTimers(); | ||
}); | ||
expect(title).toBeVisible(); | ||
}); | ||
|
||
test('If only getInfo request fails, the LoaderFailureModal appears', async () => { | ||
// TODO remove when SHELL-117 will be implemented | ||
const actualConsoleError = console.error; | ||
console.error = jest.fn<ReturnType<typeof console.error>, Parameters<typeof console.error>>( | ||
(error, ...restParameter) => { | ||
if (error === 'Unexpected end of JSON input') { | ||
console.log('Controlled error', error, ...restParameter); | ||
} else { | ||
actualConsoleError(error, ...restParameter); | ||
} | ||
} | ||
); | ||
// using getComponents and loginConfig default handlers | ||
server.use( | ||
rest.post('/service/soap/GetInfoRequest', (req, res, ctx) => | ||
res(ctx.status(503, 'Controlled error: fail getInfo request')) | ||
) | ||
); | ||
|
||
setup(<Loader />); | ||
|
||
const title = await screen.findByText('Something went wrong...'); | ||
act(() => { | ||
jest.runOnlyPendingTimers(); | ||
}); | ||
expect(title).toBeVisible(); | ||
}); | ||
|
||
test('If only loginConfig request fails, the LoaderFailureModal does not appear', async () => { | ||
// using getComponents and getInfo default handlers | ||
server.use(rest.post(LOGIN_V3_CONFIG_PATH, (req, res, ctx) => res(ctx.status(503)))); | ||
|
||
setup(<Loader />); | ||
|
||
expect(screen.queryByText('Something went wrong...')).not.toBeInTheDocument(); | ||
}); | ||
|
||
test('If Loader requests do not fail, the LoaderFailureModal does not appear', async () => { | ||
// using getComponents, loginConfig and getInfo default handlers | ||
|
||
setup(<Loader />); | ||
|
||
expect(screen.queryByText('Something went wrong...')).not.toBeInTheDocument(); | ||
}); | ||
}); |
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,93 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2021 Zextras <https://www.zextras.com> | ||
* | ||
* SPDX-License-Identifier: AGPL-3.0-only | ||
*/ | ||
|
||
import { Modal, Padding, Text } from '@zextras/carbonio-design-system'; | ||
import React, { useCallback, useEffect, useState } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { find } from 'lodash'; | ||
import { useAppStore } from '../store/app'; | ||
import { getInfo } from '../network/get-info'; | ||
import { loadApps, unloadAllApps } from './app/load-apps'; | ||
import { loginConfig } from '../network/login-config'; | ||
import { goToLogin } from '../network/go-to-login'; | ||
import { getComponents } from '../network/get-components'; | ||
|
||
export function isPromiseRejectedResult<T>( | ||
promiseSettledResult: PromiseSettledResult<T> | ||
): promiseSettledResult is PromiseRejectedResult { | ||
return promiseSettledResult.status === 'rejected'; | ||
} | ||
|
||
export function isPromiseFulfilledResult<T>( | ||
promiseSettledResult: PromiseSettledResult<T> | ||
): promiseSettledResult is PromiseFulfilledResult<T> { | ||
return promiseSettledResult.status === 'fulfilled'; | ||
} | ||
|
||
type LoaderFailureModalProps = { open: boolean; closeHandler: () => void }; | ||
|
||
export const LoaderFailureModal = ({ | ||
open, | ||
closeHandler | ||
}: LoaderFailureModalProps): JSX.Element => { | ||
const [t] = useTranslation(); | ||
const onConfirm = useCallback(() => window.location.reload(), []); | ||
return ( | ||
<Modal | ||
open={open} | ||
showCloseIcon={false} | ||
onSecondaryAction={goToLogin} | ||
title={t('bootstrap.failure.modal.title', 'Something went wrong...')} | ||
confirmLabel={t('bootstrap.failure.modal.confirmButtonLabel', 'refresh')} | ||
secondaryActionLabel={t('bootstrap.failure.modal.secondaryButtonLabel', 'login page')} | ||
onConfirm={onConfirm} | ||
onClose={closeHandler} | ||
> | ||
<Padding all="small"> | ||
<Text overflow="break-word"> | ||
{t( | ||
'bootstrap.failure.modal.body', | ||
'Some technical issues occurred while processing your request. Please try to refresh the page or go back to the login page.' | ||
)} | ||
</Text> | ||
</Padding> | ||
</Modal> | ||
); | ||
}; | ||
|
||
export const Loader = (): JSX.Element => { | ||
const [open, setOpen] = useState(false); | ||
const closeHandler = useCallback(() => setOpen(false), []); | ||
|
||
useEffect(() => { | ||
Promise.allSettled([loginConfig(), getComponents(), getInfo()]).then( | ||
(promiseSettledResultArray) => { | ||
const [, getComponentsPromiseSettledResult, getInfoPromiseSettledResult] = | ||
promiseSettledResultArray; | ||
|
||
const promiseRejectedResult = find( | ||
[getComponentsPromiseSettledResult, getInfoPromiseSettledResult], | ||
isPromiseRejectedResult | ||
); | ||
if (promiseRejectedResult) { | ||
if (typeof promiseRejectedResult.reason === 'string') { | ||
console.error(promiseRejectedResult.reason); | ||
} else if ('message' in promiseRejectedResult.reason) { | ||
console.error(promiseRejectedResult.reason.message); | ||
} | ||
setOpen(true); | ||
} | ||
if (isPromiseFulfilledResult(getComponentsPromiseSettledResult)) { | ||
loadApps(Object.values(useAppStore.getState().apps)); | ||
} | ||
} | ||
); | ||
return () => { | ||
unloadAllApps(); | ||
}; | ||
}, []); | ||
return <LoaderFailureModal open={open} closeHandler={closeHandler} />; | ||
}; |
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
Oops, something went wrong.