From 5acf315af5a71de3bff62027d718c30e04a74f73 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 30 Aug 2023 12:38:29 +0200 Subject: [PATCH] SONAR-20254 Migrate StartupModal test to RTL --- .../js/app/components/GlobalContainer.tsx | 73 +++++++------- .../main/js/app/components/StartupModal.tsx | 22 +---- .../__tests__/StartupModal-test.tsx | 97 +++++++------------ 3 files changed, 76 insertions(+), 116 deletions(-) diff --git a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx index 9ac12eddab3..802c786c127 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx @@ -61,45 +61,44 @@ export default function GlobalContainer() { - - -
-
-
- - - - -
- - - - - - {/* The following is the portal anchor point for the component nav - * See ComponentContainer.tsx - */} -
-
- - - - - -
- + +
+
+
+ + + + +
+ + + + + + {/* The following is the portal anchor point for the component nav + * See ComponentContainer.tsx + */} +
+
+ + + + +
- +
- + +
+ diff --git a/server/sonar-web/src/main/js/app/components/StartupModal.tsx b/server/sonar-web/src/main/js/app/components/StartupModal.tsx index 50b97a2df13..80b283d2331 100644 --- a/server/sonar-web/src/main/js/app/components/StartupModal.tsx +++ b/server/sonar-web/src/main/js/app/components/StartupModal.tsx @@ -21,7 +21,6 @@ import { differenceInDays } from 'date-fns'; import * as React from 'react'; import { showLicense } from '../../api/editions'; import LicensePromptModal from '../../apps/marketplace/components/LicensePromptModal'; -import { Location, Router, withRouter } from '../../components/hoc/withRouter'; import { parseDate, toShortISO8601String } from '../../helpers/dates'; import { hasMessage } from '../../helpers/l10n'; import { get, save } from '../../helpers/storage'; @@ -31,16 +30,10 @@ import { CurrentUser, isLoggedIn } from '../../types/users'; import withAppStateContext from './app-state/withAppStateContext'; import withCurrentUserContext from './current-user/withCurrentUserContext'; -interface StateProps { +interface Props { currentUser: CurrentUser; -} - -type Props = { - children?: React.ReactNode; - location: Location; - router: Router; appState: AppState; -}; +} interface State { open?: boolean; @@ -48,7 +41,7 @@ interface State { const LICENSE_PROMPT = 'sonarqube.license.prompt'; -export class StartupModal extends React.PureComponent { +export class StartupModal extends React.PureComponent { state: State = {}; componentDidMount() { @@ -82,13 +75,8 @@ export class StartupModal extends React.PureComponent render() { const { open } = this.state; - return ( - <> - {this.props.children} - {open && } - - ); + return open ? : null; } } -export default withCurrentUserContext(withRouter(withAppStateContext(StartupModal))); +export default withCurrentUserContext(withAppStateContext(StartupModal)); diff --git a/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx index 5908e9d4460..06f745cb907 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx +++ b/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx @@ -17,16 +17,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { differenceInDays } from 'date-fns'; -import { shallow, ShallowWrapper } from 'enzyme'; +import userEvent from '@testing-library/user-event'; import * as React from 'react'; -import { showLicense } from '../../../api/editions'; -import { toShortISO8601String } from '../../../helpers/dates'; -import { hasMessage } from '../../../helpers/l10n'; -import { mockLicense } from '../../../helpers/mocks/editions'; -import { get, save } from '../../../helpers/storage'; -import { mockAppState, mockLocation, mockRouter } from '../../../helpers/testMocks'; -import { waitAndUpdate } from '../../../helpers/testUtils'; +import { save } from '../../../helpers/storage'; +import { mockAppState, mockCurrentUser } from '../../../helpers/testMocks'; +import { renderApp } from '../../../helpers/testReactTestingUtils'; +import { byRole, byText } from '../../../helpers/testSelector'; import { EditionKey } from '../../../types/editions'; import { LoggedInUser } from '../../../types/users'; import { StartupModal } from '../StartupModal'; @@ -40,10 +36,6 @@ jest.mock('../../../helpers/storage', () => ({ save: jest.fn(), })); -jest.mock('../../../helpers/l10n', () => ({ - hasMessage: jest.fn().mockReturnValue(true), -})); - jest.mock('../../../helpers/dates', () => ({ parseDate: jest.fn().mockReturnValue('parsed-date'), toShortISO8601String: jest.fn().mockReturnValue('short-not-iso-date'), @@ -61,73 +53,54 @@ const LOGGED_IN_USER: LoggedInUser = { }; beforeEach(() => { - jest.mocked(differenceInDays).mockClear(); - jest.mocked(hasMessage).mockClear(); - jest.mocked(get).mockClear(); - jest.mocked(save).mockClear(); - jest.mocked(showLicense).mockClear(); - jest.mocked(toShortISO8601String).mockClear(); + jest.clearAllMocks(); }); -it('should render only the children', async () => { - const wrapper = getWrapper({ appState: mockAppState({ edition: EditionKey.community }) }); - await shouldNotHaveModals(wrapper); - expect(showLicense).toHaveBeenCalledTimes(0); - expect(wrapper.find('div').exists()).toBe(true); - - await shouldNotHaveModals(getWrapper({ appState: mockAppState({ canAdmin: false }) })); +it('should check license and open on its own', async () => { + const user = userEvent.setup(); + renderStartupModal(); - jest.mocked(hasMessage).mockReturnValueOnce(false); - await shouldNotHaveModals(getWrapper()); + await new Promise(setImmediate); - jest.mocked(showLicense).mockResolvedValueOnce(mockLicense({ isValidEdition: true })); - await shouldNotHaveModals(getWrapper()); + expect(save).toHaveBeenCalled(); + expect(ui.modalHeader.get()).toBeInTheDocument(); - jest.mocked(get).mockReturnValueOnce('date'); - jest.mocked(differenceInDays).mockReturnValueOnce(0); - await shouldNotHaveModals(getWrapper()); + await user.click(ui.licensePageLink.get()); - await shouldNotHaveModals( - getWrapper({ - appState: mockAppState({ canAdmin: false }), - currentUser: { ...LOGGED_IN_USER }, - location: mockLocation({ pathname: '/create-organization' }), - }) - ); + expect(byText('/admin/extension/license/app').get()).toBeInTheDocument(); }); -it('should render license prompt', async () => { - await shouldDisplayLicense(getWrapper()); - expect(save).toHaveBeenCalledWith('sonarqube.license.prompt', 'short-not-iso-date', 'luke'); +it.each([ + [ + 'community edition', + { appState: mockAppState({ canAdmin: true, edition: EditionKey.community }) }, + ], + ['Cannot admin', { appState: mockAppState({ canAdmin: false, edition: EditionKey.enterprise }) }], + ['User is not logged in', { currentUser: mockCurrentUser() }], +])('should not open when not necessary: %s', async (_, props: Partial) => { + renderStartupModal(props); - jest.mocked(get).mockReturnValueOnce('date'); - jest.mocked(differenceInDays).mockReturnValueOnce(1); - await shouldDisplayLicense(getWrapper()); + await new Promise(setImmediate); - jest.mocked(showLicense).mockResolvedValueOnce(mockLicense({ isValidEdition: false })); - await shouldDisplayLicense(getWrapper()); + expect(save).not.toHaveBeenCalled(); + expect(ui.modalHeader.query()).not.toBeInTheDocument(); }); -async function shouldNotHaveModals(wrapper: ShallowWrapper) { - await waitAndUpdate(wrapper); - expect(wrapper.find('LicensePromptModal').exists()).toBe(false); -} - -async function shouldDisplayLicense(wrapper: ShallowWrapper) { - await waitAndUpdate(wrapper); - expect(wrapper.find('LicensePromptModal').exists()).toBe(true); -} - -function getWrapper(props: Partial = {}) { - return shallow( +function renderStartupModal(props: Partial = {}) { + return renderApp( + '/',
); } + +const ui = { + modalHeader: byRole('heading', { name: 'license.prompt.title' }), + licensePageLink: byRole('link', { name: 'license.prompt.link' }), + modalCancelButton: byRole('button', { name: 'cancel' }), +}; -- 2.39.5