diff --git a/frontend/src/components/errorReport/index.tsx b/frontend/src/components/errorReport/index.tsx index f59c8df0e01a3a25a41d208d3cb066f878f693f8..f95a9b33dd126ce42905ec633454e2f41051a3da 100644 --- a/frontend/src/components/errorReport/index.tsx +++ b/frontend/src/components/errorReport/index.tsx @@ -15,7 +15,7 @@ export default function ServerErrorReport({ statusText, errorBodyText, }: ServerErrorReportData) { - const [t] = useTranslation(['common']) + const { t } = useTranslation(['common']) return ( <Alert severity="error"> <AlertTitle>{errorHeading}</AlertTitle> diff --git a/frontend/src/test-utils.tsx b/frontend/src/test-utils.tsx index 7be8884de2a2feb948ca530b2b2464225e5e5be5..fa8739024553136211812cbfeb356c9840f2fd8c 100644 --- a/frontend/src/test-utils.tsx +++ b/frontend/src/test-utils.tsx @@ -19,13 +19,71 @@ export * from '@testing-library/react' // override render method export { customRender as render } -// Mock react-i18next module to return a translation that just returns the key -jest.mock('react-i18next', () => ({ - useTranslation: () => ({ - t: (value: string) => value, - i18n: { - language: 'en', - changeLanguage: () => new Promise(() => {}), - }, - }), -})) +// The reason for this complex mock of react-i18next is to make the Trans-component work when running tests +jest.mock('react-i18next', (): object => { + // Need to require React at this level as well to avoid getting an error + // when running the tests saying that the module factory is not allowed + // to reference out-of-scope variables + // eslint-disable-next-line @typescript-eslint/no-shadow,global-require + const React = require('react') + + const hasChildren = (node: any): boolean => + node && (node.children || (node.props && node.props.children)) + + const getChildrenFromProps = (node: any): any => + node.props && node.props.children ? node.props.children : null + + const getChildren = (node: any): any => + node && node.children ? node.children : getChildrenFromProps(node) + + const renderNodes = (reactNodes: any): any => { + if (typeof reactNodes === 'string') { + return reactNodes + } + + return Object.keys(reactNodes).map((key, i) => { + const child = reactNodes[key] + + if (typeof child === 'string') { + return child + } + + if (hasChildren(child)) { + const inner = renderNodes(getChildren(child)) + // eslint-disable-next-line react/no-array-index-key + return React.cloneElement(child, { ...child.props, key: i }, inner) + } + + const isElement = React.isValidElement(child) + if (typeof child === 'object' && !isElement) { + return Object.keys(child).reduce( + (str, childKey) => `${str}${child[childKey]}`, + '' + ) + } + + return child + }) + } + + const useMock: any = [(k: any) => k, {}] + // Mock react-i18next module to return a translation that just returns the key + useMock.t = (k: any) => k + useMock.i18n = { + // Return "en" as the selected language if the code asks for it + language: 'en', + changeLanguage: () => new Promise(() => {}), + } + + return { + withTranslation: + () => + (Component: any): any => + (props: any): any => + <Component t={(k: any): any => k} {...props} />, + Trans: ({ children }: any) => renderNodes(children), + Translation: ({ children }: any) => + children((k: any): any => k, { i18n: {} }), + useTranslation: () => useMock, + } +})