From 430e3cac4cf1fffabbc9f19e2291ad93dd75d160 Mon Sep 17 00:00:00 2001 From: Mozafar Haider Date: Thu, 29 Aug 2024 10:29:01 +0100 Subject: [PATCH] test: add tests for ManualInstall --- jest.config.js | 12 +-- package.json | 1 + src/pages/ManualInstall/ManualInstall.js | 3 +- src/pages/ManualInstall/ManualInstall.spec.js | 93 +++++++++++++++++++ src/test-utils/MockAlertStack.js | 49 ++++++++++ src/test-utils/index.js | 1 + yarn.lock | 7 ++ 7 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 src/pages/ManualInstall/ManualInstall.spec.js create mode 100644 src/test-utils/MockAlertStack.js create mode 100644 src/test-utils/index.js diff --git a/jest.config.js b/jest.config.js index 88e1888..6da0c6b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,13 +6,13 @@ const config = { ], coverageThreshold: { global: { - // TODO: The following should be 50 - branches: 0, + // TODO: The following should be ~50% + branches: 10, - // TODO: The following should be 75 - functions: 0, - lines: 0, - statements: 0, + // TODO: The following should be ~75% + functions: 20, + lines: 20, + statements: 20, }, }, } diff --git a/package.json b/package.json index ecfabc4..0a1d264 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@dhis2/cli-style": "^10.4.1", "@testing-library/jest-dom": "^6.1.5", "@testing-library/react": "^12", + "@testing-library/user-event": "^13.5.0", "@types/jest": "^29.5.11", "jest": "^29.7.0", "react-dom": "^16" diff --git a/src/pages/ManualInstall/ManualInstall.js b/src/pages/ManualInstall/ManualInstall.js index 64a4fa6..437263f 100644 --- a/src/pages/ManualInstall/ManualInstall.js +++ b/src/pages/ManualInstall/ManualInstall.js @@ -29,7 +29,7 @@ const UploadButton = () => { const errorAlert = useAlert( ({ error }) => i18n.t('Failed to install app: {{errorMessage}}', { - errorMessage: error.message, + errorMessage: error?.message, nsSeparator: '-:-', }), { critical: true } @@ -57,6 +57,7 @@ const UploadButton = () => { <>
({ + useHistory: jest.fn(() => ({ + push: jest.fn(), + })), +})) + +const renderWithProvider = (component) => { + return render(component, { + wrapper: ({ children }) => { + return ( + + {children} + + + ) + }, + }) +} +describe('Manual Install', () => { + const historyPush = jest.fn() + + beforeEach(() => { + global.fetch = jest.fn() + useHistory.mockImplementation(() => ({ push: historyPush })) + }) + + afterEach(() => { + delete global.fetch + jest.resetAllMocks() + }) + + it('should allow navigating to the app', async () => { + jest.spyOn(global, 'fetch').mockResolvedValueOnce({ + json: () => Promise.resolve({ app_hub_id: 'some_apphub_id' }), + }) + + const { getByTestId, getByText, findByText } = renderWithProvider( + + ) + + const fileInput = getByTestId('file-upload') + userEvent.upload(fileInput, 'testfile') + + await findByText('App installed successfully') + await userEvent.click(getByText('Go to app')) + expect(historyPush).toHaveBeenCalledWith('/app/some_apphub_id') + }) + + it('should work with an empty response (pre v41)', async () => { + jest.spyOn(global, 'fetch').mockResolvedValueOnce({ + json: () => Promise.resolve(), + }) + + const { getByTestId, findByText, queryByText } = renderWithProvider( + + ) + + const fileInput = getByTestId('file-upload') + userEvent.upload(fileInput, 'testfile') + + await findByText('App installed successfully') + expect(queryByText('Go to app')).not.toBeInTheDocument() + expect(historyPush).not.toHaveBeenCalled() + }) + + it('should show an error if it fails', async () => { + jest.spyOn(global, 'fetch').mockResolvedValueOnce({ + json: () => { + throw 'upload failed' + }, + }) + + const { getByTestId, findByText, queryByText } = renderWithProvider( + + ) + + const fileInput = getByTestId('file-upload') + userEvent.upload(fileInput, 'testfile') + + await findByText('Failed to install app:') + expect(queryByText('Go to app')).not.toBeInTheDocument() + expect(historyPush).not.toHaveBeenCalled() + }) +}) diff --git a/src/test-utils/MockAlertStack.js b/src/test-utils/MockAlertStack.js new file mode 100644 index 0000000..6302d1d --- /dev/null +++ b/src/test-utils/MockAlertStack.js @@ -0,0 +1,49 @@ +import { useAlerts } from '@dhis2/app-runtime' +import PropTypes from 'prop-types' +import React, { useEffect } from 'react' + +const MockAlert = ({ alert }) => { + useEffect(() => { + if (alert.options?.duration) { + setTimeout(() => alert.remove(), alert.options?.duration) + } + }, [alert]) + return ( +
+ {alert.message} + {alert?.options?.actions?.map((action, i) => ( + + ))} +
+ ) +} + +MockAlert.propTypes = { + alert: PropTypes.shape({ + message: PropTypes.string, + options: PropTypes.shape({ + actions: PropTypes.arrayOf( + PropTypes.shape({ + label: PropTypes.string, + onClick: PropTypes.func, + }) + ), + duration: PropTypes.number, + }), + remove: PropTypes.func, + }), +} + +export const MockAlertStack = () => { + const alerts = useAlerts() + + return ( +
+ {alerts.map((alert) => ( + + ))} +
+ ) +} diff --git a/src/test-utils/index.js b/src/test-utils/index.js new file mode 100644 index 0000000..0950348 --- /dev/null +++ b/src/test-utils/index.js @@ -0,0 +1 @@ +export * from './MockAlertStack.js' diff --git a/yarn.lock b/yarn.lock index 330e6d3..3894d03 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3190,6 +3190,13 @@ "@testing-library/dom" "^8.0.0" "@types/react-dom" "<18.0.0" +"@testing-library/user-event@^13.5.0": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-13.5.0.tgz#69d77007f1e124d55314a2b73fd204b333b13295" + integrity sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg== + dependencies: + "@babel/runtime" "^7.12.5" + "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"