From c8b5142dfe1f772f212e740cf54dc487cabac83d Mon Sep 17 00:00:00 2001 From: Wouter Admiraal Date: Fri, 16 Sep 2022 16:55:53 +0200 Subject: SONAR-17027 Fix links when running in a webcontext --- .../main/js/apps/maintenance/components/App.tsx | 17 +- .../maintenance/components/__tests__/App-test.tsx | 293 ++++++++---- .../__tests__/__snapshots__/App-test.tsx.snap | 522 --------------------- .../src/main/js/apps/sessions/components/Login.tsx | 13 +- .../js/apps/sessions/components/LoginContainer.tsx | 4 +- .../main/js/apps/sessions/components/LoginForm.tsx | 3 +- .../main/js/apps/sessions/components/Logout.tsx | 2 +- .../js/apps/sessions/components/Unauthorized.tsx | 3 +- .../sessions/components/__tests__/Login-it.tsx | 144 ++++++ .../sessions/components/__tests__/Login-test.tsx | 52 -- .../components/__tests__/LoginContainer-test.tsx | 69 --- .../components/__tests__/LoginForm-test.tsx | 56 --- .../sessions/components/__tests__/Logout-it.tsx | 91 ++++ .../sessions/components/__tests__/Logout-test.tsx | 83 ---- .../components/__tests__/OAuthProviders-test.tsx | 60 --- .../components/__tests__/Unauthorized-it.tsx | 46 ++ .../components/__tests__/Unauthorized-test.tsx | 30 -- .../__tests__/__snapshots__/Login-it.tsx.snap | 19 + .../__tests__/__snapshots__/Login-test.tsx.snap | 85 ---- .../__snapshots__/LoginContainer-test.tsx.snap | 18 - .../__snapshots__/LoginForm-test.tsx.snap | 228 --------- .../__tests__/__snapshots__/Logout-test.tsx.snap | 13 - .../__snapshots__/OAuthProviders-test.tsx.snap | 84 ---- .../__snapshots__/Unauthorized-test.tsx.snap | 39 -- 24 files changed, 529 insertions(+), 1445 deletions(-) delete mode 100644 server/sonar-web/src/main/js/apps/maintenance/components/__tests__/__snapshots__/App-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/Login-it.tsx delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/Login-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginContainer-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginForm-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/Logout-it.tsx delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/Logout-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/OAuthProviders-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/Unauthorized-it.tsx delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/Unauthorized-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Login-it.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Login-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginContainer-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Logout-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/OAuthProviders-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Unauthorized-test.tsx.snap (limited to 'server/sonar-web/src/main') diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/App.tsx b/server/sonar-web/src/main/js/apps/maintenance/components/App.tsx index 7b943cf2000..4655bb62b1c 100644 --- a/server/sonar-web/src/main/js/apps/maintenance/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/maintenance/components/App.tsx @@ -45,6 +45,9 @@ interface State { wasStarting?: boolean; } +const DELAY_REDIRECT_PREV_PAGE = 2500; +const DELAY_REFRESH_STATUS = 5000; + export default class App extends React.PureComponent { interval?: number; mounted = false; @@ -109,13 +112,13 @@ export default class App extends React.PureComponent { }; scheduleRefresh = () => { - this.interval = window.setTimeout(this.fetchStatus, 5000); + this.interval = window.setTimeout(this.fetchStatus, DELAY_REFRESH_STATUS); }; loadPreviousPage = () => { setInterval(() => { - window.location.href = getReturnUrl(this.props.location); - }, 2500); + window.location.replace(getReturnUrl(this.props.location)); + }, DELAY_REDIRECT_PREV_PAGE); }; handleMigrateClick = () => { @@ -150,6 +153,7 @@ export default class App extends React.PureComponent { {translate('maintenance.sonarqube_is_offline.text')}

+ {/* We don't use here, as we want to fully refresh the page. */} {translate('maintenance.try_again')}

@@ -164,7 +168,7 @@ export default class App extends React.PureComponent { {translate('maintenance.all_systems_opetational')}

- {translate('layout.home')} + {translate('layout.home')}

)} @@ -189,6 +193,7 @@ export default class App extends React.PureComponent { {translate('maintenance.sonarqube_is_down.text')}

+ {/* We don't use here, as we want to fully refresh the page. */} {translate('maintenance.try_again')}

@@ -238,7 +243,7 @@ export default class App extends React.PureComponent { {translate('maintenance.database_is_up_to_date')}

- {translate('layout.home')} + {translate('layout.home')}

)} @@ -294,7 +299,7 @@ export default class App extends React.PureComponent { {translate('maintenance.database_is_up_to_date')}

- {translate('layout.home')} + {translate('layout.home')}

)} diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/App-test.tsx index abf658535db..98f1e8fe9fc 100644 --- a/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/App-test.tsx +++ b/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/App-test.tsx @@ -17,124 +17,245 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { shallow } from 'enzyme'; +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import * as React from 'react'; -import { click, waitAndUpdate } from '../../../../helpers/testUtils'; +import { getMigrationStatus, getSystemStatus, migrateDatabase } from '../../../../api/system'; +import { mockLocation } from '../../../../helpers/testMocks'; +import { renderApp } from '../../../../helpers/testReactTestingUtils'; import App from '../App'; jest.mock('../../../../api/system', () => ({ - getMigrationStatus: jest.fn(), - getSystemStatus: jest.fn(), - migrateDatabase: jest.fn() + getMigrationStatus: jest.fn().mockResolvedValue(null), + getSystemStatus: jest.fn().mockResolvedValue(null), + migrateDatabase: jest.fn().mockResolvedValue(null) })); +jest.mock('../../../../helpers/system', () => ({ + ...jest.requireActual('../../../../helpers/system'), + getBaseUrl: jest.fn().mockReturnValue('/context') +})); + +const originalLocation = window.location; +const replace = jest.fn(); + beforeAll(() => { jest.useFakeTimers(); + + const location = { + ...window.location, + replace + }; + Object.defineProperty(window, 'location', { + writable: true, + value: location + }); }); afterAll(() => { jest.runOnlyPendingTimers(); jest.useRealTimers(); -}); -const getMigrationStatus = require('../../../../api/system').getMigrationStatus as jest.Mock; -const getSystemStatus = require('../../../../api/system').getSystemStatus as jest.Mock; -const migrateDatabase = require('../../../../api/system').migrateDatabase as jest.Mock; - -const location = { query: {} }; - -beforeEach(() => { - getMigrationStatus.mockClear(); - getSystemStatus.mockClear(); - migrateDatabase.mockClear(); + Object.defineProperty(window, 'location', { + writable: true, + value: originalLocation + }); }); -afterEach(() => { - jest.clearAllTimers(); -}); +beforeEach(jest.clearAllMocks); -describe('Maintenance Page', () => { - ['UP', 'DOWN', 'STARTING', 'DB_MIGRATION_NEEDED', 'DB_MIGRATION_RUNNING'].forEach(status => { - it(`should render ${status} status`, async () => { - getSystemStatus.mockImplementationOnce(() => Promise.resolve({ status })); - await checkApp(false); - }); - }); +describe('Maintenance', () => { + it.each([ + [ + 'OFFLINE', + 'maintenance.is_offline', + 'maintenance.sonarqube_is_offline.text', + { name: 'maintenance.try_again', href: '/context/' } + ], + [ + 'UP', + 'maintenance.is_up', + 'maintenance.all_systems_opetational', + { name: 'layout.home', href: '/' } + ], + ['STARTING', 'maintenance.is_starting'], + [ + 'DOWN', + 'maintenance.is_down', + 'maintenance.sonarqube_is_down.text', + { name: 'maintenance.try_again', href: '/context/' } + ], + ['DB_MIGRATION_NEEDED', 'maintenance.is_under_maintenance'], + ['DB_MIGRATION_RUNNING', 'maintenance.is_under_maintenance'] + ])( + 'should handle "%p" status correctly', + async (status, heading, body = undefined, linkInfo = undefined) => { + (getSystemStatus as jest.Mock).mockResolvedValueOnce({ status }); + renderMaintenanceApp(); - it('should render OFFLINE status', async () => { - getSystemStatus.mockImplementationOnce(() => Promise.reject(undefined)); - await checkApp(false); - }); + const title = await screen.findByRole('heading', { name: heading }); + expect(title).toBeInTheDocument(); + if (body) { + expect(screen.getByText(body)).toBeInTheDocument(); + } + if (linkInfo) { + const link = screen.getByRole('link', { name: linkInfo.name }); + expect(link).toBeInTheDocument(); + expect(link).toHaveAttribute('href', linkInfo.href); + } + } + ); it('should poll status', async () => { - getSystemStatus.mockImplementationOnce(() => - Promise.resolve({ status: 'DB_MIGRATION_RUNNING' }) - ); - const wrapper = shallow(); - await waitAndUpdate(wrapper); - expect(getSystemStatus).toBeCalled(); + (getSystemStatus as jest.Mock) + .mockResolvedValueOnce({ status: 'STARTING' }) + .mockResolvedValueOnce({ status: 'DB_MIGRATION_RUNNING' }) + .mockResolvedValueOnce({ status: 'UP' }); + + renderMaintenanceApp(); + + let title = await screen.findByRole('heading', { name: 'maintenance.is_starting' }); + expect(title).toBeInTheDocument(); - getSystemStatus.mockClear(); - getSystemStatus.mockImplementationOnce(() => - Promise.resolve({ status: 'DB_MIGRATION_RUNNING' }) - ); jest.runOnlyPendingTimers(); - await waitAndUpdate(wrapper); - expect(getSystemStatus).toBeCalled(); - getSystemStatus.mockClear(); - getSystemStatus.mockImplementationOnce(() => - Promise.resolve({ status: 'DB_MIGRATION_RUNNING' }) - ); + title = await screen.findByRole('heading', { name: 'maintenance.is_under_maintenance' }); + expect(title).toBeInTheDocument(); + jest.runOnlyPendingTimers(); - await waitAndUpdate(wrapper); - expect(getSystemStatus).toBeCalled(); - }); - it('should open previous page', async () => { - getSystemStatus.mockImplementationOnce(() => Promise.resolve({ status: 'STARTING' })); - const wrapper = shallow(); - const loadPreviousPage = jest.fn(); - (wrapper.instance() as App).loadPreviousPage = loadPreviousPage; - await waitAndUpdate(wrapper); + title = await screen.findByRole('heading', { name: 'maintenance.is_up' }); + expect(title).toBeInTheDocument(); - getSystemStatus.mockImplementationOnce(() => Promise.resolve({ status: 'UP' })); + // Should redirect automatically. jest.runOnlyPendingTimers(); - await waitAndUpdate(wrapper); - expect(loadPreviousPage).toBeCalled(); + expect(replace).toHaveBeenCalledWith('/return/to'); }); + + function renderMaintenanceApp(props: Partial = {}) { + return renderApp( + '/', + + ); + } }); -describe('Setup Page', () => { - ['NO_MIGRATION', 'NOT_SUPPORTED', 'MIGRATION_SUCCEEDED', 'MIGRATION_FAILED'].forEach(state => { - it(`should render ${state} state`, async () => { - getMigrationStatus.mockImplementationOnce(() => - Promise.resolve({ message: 'message', startedAt: '2017-01-02T00:00:00.000Z', state }) - ); - await checkApp(true); +describe('Setup', () => { + it.each([ + [ + 'NO_MIGRATION', + 'maintenance.database_is_up_to_date', + undefined, + { name: 'layout.home', href: '/' } + ], + [ + 'MIGRATION_REQUIRED', + 'maintenance.upgrade_database', + [ + 'maintenance.upgrade_database.1', + 'maintenance.upgrade_database.2', + 'maintenance.upgrade_database.3' + ] + ], + [ + 'NOT_SUPPORTED', + 'maintenance.migration_not_supported', + ['maintenance.migration_not_supported.text'] + ], + [ + 'MIGRATION_RUNNING', + 'maintenance.database_migration', + undefined, + undefined, + { message: 'MESSAGE', startedAt: '2022-12-01' } + ], + [ + 'MIGRATION_SUCCEEDED', + 'maintenance.database_is_up_to_date', + undefined, + { name: 'layout.home', href: '/' } + ], + ['MIGRATION_FAILED', 'maintenance.upgrade_failed', ['maintenance.upgrade_failed.text']] + ])( + 'should handle "%p" state correctly', + async (state, heading, bodyText: string[] = [], linkInfo = undefined, payload = undefined) => { + (getMigrationStatus as jest.Mock).mockResolvedValueOnce({ state, ...payload }); + renderSetupApp(); + + const title = await screen.findByRole('heading', { name: heading }); + expect(title).toBeInTheDocument(); + if (bodyText.length) { + bodyText.forEach(text => { + expect(screen.getByText(text)).toBeInTheDocument(); + }); + } + if (payload) { + expect(screen.getByText(payload.message)).toBeInTheDocument(); + expect(screen.getByText('background_tasks.table.started')).toBeInTheDocument(); + } + if (linkInfo) { + const link = screen.getByRole('link', { name: linkInfo.name }); + expect(link).toBeInTheDocument(); + expect(link).toHaveAttribute('href', linkInfo.href); + } + } + ); + + it('should handle DB migration', async () => { + (migrateDatabase as jest.Mock).mockResolvedValueOnce({ + message: 'MESSAGE', + startedAt: '2022-12-01', + state: 'MIGRATION_RUNNING' }); + (getMigrationStatus as jest.Mock) + .mockResolvedValueOnce({ state: 'MIGRATION_REQUIRED' }) + .mockResolvedValueOnce({ state: 'MIGRATION_RUNNING' }) + .mockResolvedValueOnce({ state: 'MIGRATION_SUCCEEDED' }); + + renderSetupApp(); + const user = userEvent.setup(); + + jest.runOnlyPendingTimers(); + + let title = await screen.findByRole('heading', { name: 'maintenance.upgrade_database' }); + expect(title).toBeInTheDocument(); + + // Trigger DB migration. + user.click(screen.getByRole('button')); + + const message = await screen.findByText('MESSAGE'); + expect(message).toBeInTheDocument(); + expect(screen.getByText('background_tasks.table.started')).toBeInTheDocument(); + + // Trigger refresh; migration running. + jest.runOnlyPendingTimers(); + + title = await screen.findByRole('heading', { name: 'maintenance.database_migration' }); + expect(title).toBeInTheDocument(); + + // Trigger refresh; migration done. + jest.runOnlyPendingTimers(); + + title = await screen.findByRole('heading', { name: 'maintenance.database_is_up_to_date' }); + expect(title).toBeInTheDocument(); + + // Should redirect automatically. + jest.runOnlyPendingTimers(); + expect(replace).toHaveBeenCalledWith('/return/to'); }); - it('should start migration', async () => { - getMigrationStatus.mockImplementationOnce(() => - Promise.resolve({ state: 'MIGRATION_REQUIRED' }) - ); - migrateDatabase.mockImplementationOnce(() => - Promise.resolve({ startedAt: '2017-01-02T00:00:00.000Z', state: 'MIGRATION_RUNNING' }) + function renderSetupApp(props: Partial = {}) { + return renderApp( + '/', + ); - const wrapper = shallow(); - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot(); - - click(wrapper.find('Button')); - expect(migrateDatabase).toBeCalled(); - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot(); - }); + } }); - -async function checkApp(setup: boolean) { - const wrapper = shallow(); - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot(); -} diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/__snapshots__/App-test.tsx.snap deleted file mode 100644 index 0dc87dd0165..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/__snapshots__/App-test.tsx.snap +++ /dev/null @@ -1,522 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Maintenance Page should render DB_MIGRATION_NEEDED status 1`] = ` - - -
-
-

- -

-

- - maintenance.sonarqube_is_under_maintenance_link.1 - , - } - } - /> -

-

- - maintenance.sonarqube_is_under_maintenance_link.2 - , - } - } - /> -

-
-
-
-`; - -exports[`Maintenance Page should render DB_MIGRATION_RUNNING status 1`] = ` - - -
-
-

- -

-

- - maintenance.sonarqube_is_under_maintenance_link.1 - , - } - } - /> -

-

- - maintenance.sonarqube_is_under_maintenance_link.2 - , - } - } - /> -

-
-
-
-`; - -exports[`Maintenance Page should render DOWN status 1`] = ` - - -
-
-

- -

-

- maintenance.sonarqube_is_down.text -

-

- - maintenance.try_again - -

-
-
-
-`; - -exports[`Maintenance Page should render OFFLINE status 1`] = ` - - -
-
-

- -

-

- maintenance.sonarqube_is_offline.text -

-

- - maintenance.try_again - -

-
-
-
-`; - -exports[`Maintenance Page should render STARTING status 1`] = ` - - -
-
-

- -

-

- -

-
-
-
-`; - -exports[`Maintenance Page should render UP status 1`] = ` - - -
-
-

- -

-

- maintenance.all_systems_opetational -

-

- - layout.home - -

-
-
-
-`; - -exports[`Setup Page should render MIGRATION_FAILED state 1`] = ` - - -
-
-

- maintenance.upgrade_failed -

-

- maintenance.upgrade_failed.text -

-
-
-
-`; - -exports[`Setup Page should render MIGRATION_SUCCEEDED state 1`] = ` - - -
-
-

- maintenance.database_is_up_to_date -

-

- - layout.home - -

-
-
-
-`; - -exports[`Setup Page should render NO_MIGRATION state 1`] = ` - - -
-
-

- maintenance.database_is_up_to_date -

-

- - layout.home - -

-
-
-
-`; - -exports[`Setup Page should render NOT_SUPPORTED state 1`] = ` - - -
-
-

- maintenance.migration_not_supported -

-

- maintenance.migration_not_supported.text -

-
-
-
-`; - -exports[`Setup Page should start migration 1`] = ` - - -
-
-

- maintenance.upgrade_database -

-

- maintenance.upgrade_database.1 -

-

- maintenance.upgrade_database.2 -

-

- maintenance.upgrade_database.3 -

-
- -
-
-
-
-`; - -exports[`Setup Page should start migration 2`] = ` - - -
-
-

- maintenance.database_migration -

-

- background_tasks.table.started - - -
- - - -

-

- -

-
-
-
-`; diff --git a/server/sonar-web/src/main/js/apps/sessions/components/Login.tsx b/server/sonar-web/src/main/js/apps/sessions/components/Login.tsx index 1de29b310b3..0cf55cf408b 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/Login.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/Login.tsx @@ -18,9 +18,10 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { Location, withRouter } from '../../../components/hoc/withRouter'; +import { Location } from '../../../components/hoc/withRouter'; import { Alert } from '../../../components/ui/Alert'; import { translate } from '../../../helpers/l10n'; +import { getReturnUrl } from '../../../helpers/urls'; import { IdentityProvider } from '../../../types/types'; import './Login.css'; import LoginForm from './LoginForm'; @@ -29,13 +30,13 @@ import OAuthProviders from './OAuthProviders'; export interface LoginProps { identityProviders: IdentityProvider[]; onSubmit: (login: string, password: string) => Promise; - returnTo: string; location: Location; } -export function Login(props: LoginProps) { - const { identityProviders, returnTo, location } = props; - const displayError = location.query.authorizationError; +export default function Login(props: LoginProps) { + const { identityProviders, location } = props; + const returnTo = getReturnUrl(location); + const displayError = Boolean(location.query.authorizationError); return (
@@ -57,5 +58,3 @@ export function Login(props: LoginProps) {
); } - -export default withRouter(Login); diff --git a/server/sonar-web/src/main/js/apps/sessions/components/LoginContainer.tsx b/server/sonar-web/src/main/js/apps/sessions/components/LoginContainer.tsx index 460ce54cd4a..3ada4d40012 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/LoginContainer.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/LoginContainer.tsx @@ -58,7 +58,7 @@ export class LoginContainer extends React.PureComponent { } handleSuccessfulLogin = () => { - window.location.href = getReturnUrl(this.props.location); + window.location.replace(getReturnUrl(this.props.location)); }; handleSubmit = (id: string, password: string) => { @@ -82,7 +82,7 @@ export class LoginContainer extends React.PureComponent { ); } diff --git a/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx b/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx index ee96583d823..649efae5ecd 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx @@ -22,7 +22,6 @@ import Link from '../../../components/common/Link'; import { ButtonLink, SubmitButton } from '../../../components/controls/buttons'; import DeferredSpinner from '../../../components/ui/DeferredSpinner'; import { translate } from '../../../helpers/l10n'; -import { getBaseUrl } from '../../../helpers/system'; import './LoginForm.css'; interface Props { @@ -125,7 +124,7 @@ export default class LoginForm extends React.PureComponent { {translate('sessions.log_in')} - + {translate('cancel')} diff --git a/server/sonar-web/src/main/js/apps/sessions/components/Logout.tsx b/server/sonar-web/src/main/js/apps/sessions/components/Logout.tsx index 95bc68c8896..f87554c525d 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/Logout.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/Logout.tsx @@ -24,7 +24,7 @@ import { addGlobalErrorMessage } from '../../../helpers/globalMessages'; import { translate } from '../../../helpers/l10n'; import { getBaseUrl } from '../../../helpers/system'; -export default class Logout extends React.PureComponent<{}> { +export default class Logout extends React.PureComponent { componentDidMount() { logOut() .then(() => { diff --git a/server/sonar-web/src/main/js/apps/sessions/components/Unauthorized.tsx b/server/sonar-web/src/main/js/apps/sessions/components/Unauthorized.tsx index df989d43cf9..b8b61712f7c 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/Unauthorized.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/Unauthorized.tsx @@ -21,7 +21,6 @@ import * as React from 'react'; import Link from '../../../components/common/Link'; import { getCookie } from '../../../helpers/cookies'; import { translate } from '../../../helpers/l10n'; -import { getBaseUrl } from '../../../helpers/system'; export default function Unauthorized() { const message = decodeURIComponent(getCookie('AUTHENTICATION-ERROR') || ''); @@ -38,7 +37,7 @@ export default function Unauthorized() { )}
- {translate('layout.home')} + {translate('layout.home')}
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Login-it.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Login-it.tsx new file mode 100644 index 00000000000..70ac5f61ec6 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Login-it.tsx @@ -0,0 +1,144 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import * as React from 'react'; +import { getIdentityProviders } from '../../../../api/users'; +import { addGlobalErrorMessage } from '../../../../helpers/globalMessages'; +import { mockLocation } from '../../../../helpers/testMocks'; +import { renderComponent } from '../../../../helpers/testReactTestingUtils'; +import { LoginContainer } from '../LoginContainer'; + +jest.mock('../../../../api/users', () => { + const { mockIdentityProvider } = jest.requireActual('../../../../helpers/testMocks'); + return { + getIdentityProviders: jest + .fn() + .mockResolvedValue({ identityProviders: [mockIdentityProvider()] }) + }; +}); + +jest.mock('../../../../api/auth', () => ({ + logIn: jest.fn((_id, password) => (password === 'valid' ? Promise.resolve() : Promise.reject())) +})); + +jest.mock('../../../../helpers/globalMessages', () => ({ + addGlobalErrorMessage: jest.fn() +})); + +const originalLocation = window.location; +const replace = jest.fn(); + +beforeAll(() => { + const location = { + ...window.location, + replace + }; + Object.defineProperty(window, 'location', { + writable: true, + value: location + }); +}); + +afterAll(() => { + Object.defineProperty(window, 'location', { + writable: true, + value: originalLocation + }); +}); + +beforeEach(jest.clearAllMocks); + +it('should behave correctly', async () => { + renderLoginContainer(); + const user = userEvent.setup(); + + const heading = await screen.findByRole('heading', { name: 'login.login_to_sonarqube' }); + expect(heading).toBeInTheDocument(); + + // OAuth provider. + const link = screen.getByRole('link', { name: 'Github login.login_with_x.Github' }); + expect(link).toBeInTheDocument(); + expect(link).toHaveAttribute('href', '/sessions/init/github?return_to=%2Fsome%2Fpath'); + expect(link).toMatchSnapshot('OAuthProvider link'); + + // Login form collapsed by default. + expect(screen.queryByLabelText('login')).not.toBeInTheDocument(); + + // Open login form, log in. + await user.click(screen.getByRole('button', { name: 'login.more_options' })); + + const cancelLink = await screen.findByRole('link', { name: 'cancel' }); + expect(cancelLink).toBeInTheDocument(); + expect(cancelLink).toHaveAttribute('href', '/'); + + const loginField = screen.getByLabelText('login'); + const passwordField = screen.getByLabelText('password'); + const submitButton = screen.getByRole('button', { name: 'sessions.log_in' }); + + // Incorrect login. + await user.type(loginField, 'janedoe'); + await user.type(passwordField, 'invalid'); + // Don't use userEvent.click() here. This allows us to more easily see the loading state changes. + submitButton.click(); + expect(submitButton).toBeDisabled(); // Loading. + await waitFor(() => { + expect(addGlobalErrorMessage).toHaveBeenCalledWith('login.authentication_failed'); + }); + + // Correct login. + await user.clear(passwordField); + await user.type(passwordField, 'valid'); + await user.click(submitButton); + expect(addGlobalErrorMessage).toHaveBeenCalledTimes(1); + expect(replace).toHaveBeenCalledWith('/some/path'); +}); + +it('should not show any OAuth providers if none are configured', async () => { + (getIdentityProviders as jest.Mock).mockResolvedValueOnce({ identityProviders: [] }); + renderLoginContainer(); + + const heading = await screen.findByRole('heading', { name: 'login.login_to_sonarqube' }); + expect(heading).toBeInTheDocument(); + + // No OAuth providers, login form display by default. + expect( + screen.queryByRole('link', { name: 'login.login_with_x', exact: false }) + ).not.toBeInTheDocument(); + expect(screen.getByLabelText('login')).toBeInTheDocument(); +}); + +it("should show a warning if there's an authorization error", async () => { + renderLoginContainer({ + location: mockLocation({ query: { authorizationError: 'true' } }) + }); + + const heading = await screen.findByRole('heading', { name: 'login.login_to_sonarqube' }); + expect(heading).toBeInTheDocument(); + + expect(screen.getByRole('alert')).toBeInTheDocument(); + expect(screen.getByText('login.unauthorized_access_alert')).toBeInTheDocument(); +}); + +function renderLoginContainer(props: Partial = {}) { + return renderComponent( + + ); +} diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Login-test.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Login-test.tsx deleted file mode 100644 index 5f1071ea4dc..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Login-test.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { shallow } from 'enzyme'; -import * as React from 'react'; -import { mockLocation } from '../../../../helpers/testMocks'; -import { Login, LoginProps } from '../Login'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('with identity providers'); - expect(shallowRender({ identityProviders: [] })).toMatchSnapshot( - 'without any identity providers' - ); - expect( - shallowRender({ location: mockLocation({ query: { authorizationError: true } }) }) - ).toMatchSnapshot('with authorization error'); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginContainer-test.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginContainer-test.tsx deleted file mode 100644 index 510f7c4074f..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginContainer-test.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { shallow } from 'enzyme'; -import * as React from 'react'; -import { logIn } from '../../../../api/auth'; -import { getIdentityProviders } from '../../../../api/users'; -import { mockLocation } from '../../../../helpers/testMocks'; -import { waitAndUpdate } from '../../../../helpers/testUtils'; -import { LoginContainer } from '../LoginContainer'; - -jest.mock('../../../../api/users', () => { - const { mockIdentityProvider } = jest.requireActual('../../../../helpers/testMocks'); - return { - getIdentityProviders: jest - .fn() - .mockResolvedValue({ identityProviders: [mockIdentityProvider()] }) - }; -}); - -jest.mock('../../../../api/auth', () => ({ - logIn: jest.fn().mockResolvedValue({}) -})); - -beforeEach(jest.clearAllMocks); - -it('should render correctly', async () => { - const wrapper = shallowRender(); - await waitAndUpdate(wrapper); - - expect(wrapper).toMatchSnapshot(); - expect(getIdentityProviders).toBeCalled(); -}); - -it('should not provide any options if no IdPs are present', async () => { - (getIdentityProviders as jest.Mock).mockResolvedValue({}); - const wrapper = shallowRender(); - await waitAndUpdate(wrapper); - - expect(wrapper.type()).toBeNull(); - expect(getIdentityProviders).toBeCalled(); -}); - -it('should handle submission', () => { - (logIn as jest.Mock).mockResolvedValue(null); - const wrapper = shallowRender(); - wrapper.instance().handleSubmit('user', 'pass'); - expect(logIn).toBeCalledWith('user', 'pass'); -}); - -function shallowRender(props: Partial = {}) { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginForm-test.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginForm-test.tsx deleted file mode 100644 index 5f3b1b64385..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginForm-test.tsx +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { shallow } from 'enzyme'; -import * as React from 'react'; -import { change, click, submit, waitAndUpdate } from '../../../../helpers/testUtils'; -import LoginForm from '../LoginForm'; - -it('logs in with simple credentials', () => { - const onSubmit = jest.fn(() => Promise.resolve()); - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - - change(wrapper.find('#login'), 'admin'); - change(wrapper.find('#password'), 'admin'); - submit(wrapper.find('form')); - - expect(onSubmit).toBeCalledWith('admin', 'admin'); -}); - -it('should display a spinner and disabled button while loading', async () => { - const onSubmit = jest.fn(() => Promise.resolve()); - const wrapper = shallow(); - - change(wrapper.find('#login'), 'admin'); - change(wrapper.find('#password'), 'admin'); - submit(wrapper.find('form')); - wrapper.update(); - expect(wrapper).toMatchSnapshot(); - - await waitAndUpdate(wrapper); -}); - -it('expands more options', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - - click(wrapper.find('.js-more-options')); - expect(wrapper).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Logout-it.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Logout-it.tsx new file mode 100644 index 00000000000..a211ec6e648 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Logout-it.tsx @@ -0,0 +1,91 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { screen, waitFor } from '@testing-library/react'; +import * as React from 'react'; +import { logOut } from '../../../../api/auth'; +import RecentHistory from '../../../../app/components/RecentHistory'; +import { addGlobalErrorMessage } from '../../../../helpers/globalMessages'; +import { renderComponent } from '../../../../helpers/testReactTestingUtils'; +import Logout from '../Logout'; + +jest.mock('../../../../api/auth', () => ({ + logOut: jest.fn().mockResolvedValue(true) +})); + +jest.mock('../../../../helpers/globalMessages', () => ({ + addGlobalErrorMessage: jest.fn() +})); + +jest.mock('../../../../helpers/system', () => ({ + getBaseUrl: jest.fn().mockReturnValue('/context') +})); + +jest.mock('../../../../app/components/RecentHistory', () => ({ + __esModule: true, + default: { + clear: jest.fn() + } +})); + +const originalLocation = window.location; +const replace = jest.fn(); + +beforeAll(() => { + const location = { + ...window.location, + replace + }; + Object.defineProperty(window, 'location', { + writable: true, + value: location + }); +}); + +afterAll(() => { + Object.defineProperty(window, 'location', { + writable: true, + value: originalLocation + }); +}); + +beforeEach(jest.clearAllMocks); + +it('should behave correctly', async () => { + renderLogout(); + + expect(screen.getByText('logging_out')).toBeInTheDocument(); + await waitFor(() => { + expect(replace).toHaveBeenCalledWith('/context/'); + }); + expect(RecentHistory.clear).toHaveBeenCalled(); +}); + +it('should correctly handle a failing log out', async () => { + (logOut as jest.Mock).mockRejectedValueOnce(false); + renderLogout(); + + await waitFor(() => { + expect(addGlobalErrorMessage).toHaveBeenCalledWith('login.logout_failed'); + }); +}); + +function renderLogout() { + return renderComponent(); +} diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Logout-test.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Logout-test.tsx deleted file mode 100644 index 9ff8fa85c6f..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Logout-test.tsx +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { shallow } from 'enzyme'; -import * as React from 'react'; -import { logOut } from '../../../../api/auth'; -import { addGlobalErrorMessage } from '../../../../helpers/globalMessages'; -import { waitAndUpdate } from '../../../../helpers/testUtils'; -import Logout from '../Logout'; - -jest.mock('../../../../api/auth', () => ({ - logOut: jest.fn().mockResolvedValue(true) -})); - -jest.mock('../../../../helpers/globalMessages', () => ({ - addGlobalErrorMessage: jest.fn() -})); - -const originalLocation = window.location; -beforeAll(() => { - const location = { - ...window.location, - replace: jest.fn() - }; - Object.defineProperty(window, 'location', { - writable: true, - value: location - }); -}); - -beforeEach(() => { - jest.clearAllMocks(); -}); - -afterAll(() => { - Object.defineProperty(window, 'location', { - writable: true, - value: originalLocation - }); -}); - -it('should logout correctly', async () => { - (logOut as jest.Mock).mockResolvedValue(true); - - const wrapper = shallowRender(); - await waitAndUpdate(wrapper); - - expect(logOut).toHaveBeenCalled(); - expect(window.location.replace).toHaveBeenCalledWith('/'); - expect(addGlobalErrorMessage).not.toHaveBeenCalled(); -}); - -it('should not redirect if logout fails', async () => { - (logOut as jest.Mock).mockRejectedValue(false); - - const wrapper = shallowRender(); - await waitAndUpdate(wrapper); - - expect(logOut).toHaveBeenCalled(); - expect(window.location.replace).not.toHaveBeenCalled(); - expect(addGlobalErrorMessage).toHaveBeenCalled(); - expect(wrapper).toMatchSnapshot(); -}); - -function shallowRender() { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/OAuthProviders-test.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/OAuthProviders-test.tsx deleted file mode 100644 index be169509357..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/OAuthProviders-test.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { shallow } from 'enzyme'; -import * as React from 'react'; -import OAuthProviders from '../OAuthProviders'; - -const identityProviders = [ - { - backgroundColor: '#000', - iconPath: '/some/path', - key: 'foo', - name: 'Foo' - }, - { - backgroundColor: '#00F', - helpMessage: 'Help message!', - iconPath: '/icon/path', - key: 'bar', - name: 'Bar' - } -]; - -it('should render correctly', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - wrapper.find('OAuthProvider').forEach(node => expect(node.dive()).toMatchSnapshot()); -}); - -it('should use the custom label formatter', () => { - const wrapper = shallow( - 'custom_format.' + name} - identityProviders={[identityProviders[0]]} - returnTo="" - /> - ); - expect( - wrapper - .find('OAuthProvider') - .first() - .dive() - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Unauthorized-it.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Unauthorized-it.tsx new file mode 100644 index 00000000000..ddbf360f5b3 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Unauthorized-it.tsx @@ -0,0 +1,46 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { screen } from '@testing-library/react'; +import * as React from 'react'; +import { getCookie } from '../../../../helpers/cookies'; +import { renderComponent } from '../../../../helpers/testReactTestingUtils'; +import Unauthorized from '../Unauthorized'; + +jest.mock('../../../../helpers/cookies', () => ({ + getCookie: jest.fn() +})); + +it('should render correctly', () => { + renderUnauthorized(); + expect(screen.getByText('unauthorized.message')).toBeInTheDocument(); + expect(screen.queryByText('REASON')).not.toBeInTheDocument(); + expect(screen.getByRole('link', { name: 'layout.home' })).toBeInTheDocument(); +}); + +it('should correctly get the reason from the cookie', () => { + (getCookie as jest.Mock).mockReturnValueOnce('REASON'); + renderUnauthorized(); + expect(screen.getByText('unauthorized.reason REASON')).toBeInTheDocument(); +}); + +function renderUnauthorized() { + return renderComponent(); +} diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Unauthorized-test.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Unauthorized-test.tsx deleted file mode 100644 index 392ac1d59c7..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/Unauthorized-test.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { shallow } from 'enzyme'; -import * as React from 'react'; -import Unauthorized from '../Unauthorized'; - -jest.mock('../../../../helpers/cookies', () => ({ - getCookie: jest.fn().mockReturnValue('Foo') -})); - -it('render', () => { - expect(shallow()).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Login-it.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Login-it.tsx.snap new file mode 100644 index 00000000000..96449a1dc42 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Login-it.tsx.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should behave correctly: OAuthProvider link 1`] = ` + + Github + + login.login_with_x.Github + + +`; diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Login-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Login-test.tsx.snap deleted file mode 100644 index 22b570e17b1..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Login-test.tsx.snap +++ /dev/null @@ -1,85 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: with authorization error 1`] = ` -
-

- login.login_to_sonarqube -

- - login.unauthorized_access_alert - - - -
-`; - -exports[`should render correctly: with identity providers 1`] = ` -
-

- login.login_to_sonarqube -

- - -
-`; - -exports[`should render correctly: without any identity providers 1`] = ` -
-

- login.login_to_sonarqube -

- -
-`; diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginContainer-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginContainer-test.tsx.snap deleted file mode 100644 index c37fa66d43a..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginContainer-test.tsx.snap +++ /dev/null @@ -1,18 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` - -`; diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.tsx.snap deleted file mode 100644 index 10720b42939..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.tsx.snap +++ /dev/null @@ -1,228 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`expands more options 1`] = ` -
- - login.more_options - -
-`; - -exports[`expands more options 2`] = ` -
-
- - -
-
- - -
-
-
- - - sessions.log_in - - - cancel - -
-
-
-`; - -exports[`logs in with simple credentials 1`] = ` -
-
- - -
-
- - -
-
-
- - - sessions.log_in - - - cancel - -
-
-
-`; - -exports[`should display a spinner and disabled button while loading 1`] = ` -
-
- - -
-
- - -
-
-
- - - sessions.log_in - - - cancel - -
-
-
-`; diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Logout-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Logout-test.tsx.snap deleted file mode 100644 index 49bf97a3c59..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Logout-test.tsx.snap +++ /dev/null @@ -1,13 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should not redirect if logout fails 1`] = ` -
-
- logging_out -
-
-`; diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/OAuthProviders-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/OAuthProviders-test.tsx.snap deleted file mode 100644 index 156489e9ba5..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/OAuthProviders-test.tsx.snap +++ /dev/null @@ -1,84 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` - - - - -`; - -exports[`should render correctly 2`] = ` - - - - login.login_with_x.Foo - - - -`; - -exports[`should render correctly 3`] = ` - - - - login.login_with_x.Bar - - - - -`; - -exports[`should use the custom label formatter 1`] = ` - - - - custom_format.Foo - - - -`; diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Unauthorized-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Unauthorized-test.tsx.snap deleted file mode 100644 index 2e4e329391b..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/Unauthorized-test.tsx.snap +++ /dev/null @@ -1,39 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`render 1`] = ` -
-
-
-

- unauthorized.message -

-

- unauthorized.reason - - Foo -

-
- - layout.home - -
-
-
-
-`; -- cgit v1.2.3