From 6c0159dda108f42c4a68949443b566954eff2798 Mon Sep 17 00:00:00 2001 From: Viktor Vorona Date: Wed, 5 Jul 2023 14:57:30 +0200 Subject: [PATCH] SONAR-18427 RTL Migration Marketplace --- .../main/js/api/mocks/PluginsServiceMock.ts | 241 ++++++++ .../main/js/api/mocks/SettingsServiceMock.ts | 7 + server/sonar-web/src/main/js/api/plugins.ts | 81 +-- .../src/main/js/apps/marketplace/App.tsx | 20 +- .../marketplace/MarketplaceAppContainer.tsx | 2 +- .../main/js/apps/marketplace/PluginsList.tsx | 3 +- .../apps/marketplace/__tests__/App-test.tsx | 118 ---- .../__tests__/EditionBoxes-test.tsx | 47 -- .../marketplace/__tests__/Footer-test.tsx | 26 - .../marketplace/__tests__/Header-test.tsx | 28 - .../__tests__/MarketplaceApp-it.tsx | 279 +++++++++ .../MarketplaceAppContainer-test.tsx | 48 -- .../__tests__/PluginUpdates-test.tsx | 51 -- .../__tests__/PluginsList-test.tsx | 52 -- .../__tests__/__snapshots__/App-test.tsx.snap | 254 -------- .../__snapshots__/EditionBoxes-test.tsx.snap | 94 --- .../__snapshots__/Footer-test.tsx.snap | 9 - .../__snapshots__/Header-test.tsx.snap | 47 -- .../MarketplaceAppContainer-test.tsx.snap | 52 -- .../__snapshots__/PluginUpdates-test.tsx.snap | 78 --- .../__snapshots__/PluginsList-test.tsx.snap | 204 ------- .../marketplace/components/PluginActions.tsx | 4 +- .../components/PluginChangeLog.tsx | 2 +- .../components/PluginUpdateItem.tsx | 63 +- .../components/__tests__/EditionBox-test.tsx | 37 -- .../__tests__/PluginActions-test.tsx | 58 -- .../__tests__/PluginAvailable-test.tsx | 63 -- .../__tests__/PluginChangeLog-test.tsx | 67 --- .../__tests__/PluginDescription-test.tsx | 46 -- .../__tests__/PluginLicense-test.tsx | 30 - .../__tests__/PluginOrganization-test.tsx | 43 -- .../__tests__/PluginRiskConsentBox-test.tsx | 39 -- .../components/__tests__/PluginUrls-test.tsx | 49 -- .../__snapshots__/EditionBox-test.tsx.snap | 83 --- .../__snapshots__/PluginActions-test.tsx.snap | 116 ---- .../PluginAvailable-test.tsx.snap | 550 ------------------ .../PluginChangeLog-test.tsx.snap | 105 ---- .../PluginDescription-test.tsx.snap | 44 -- .../__snapshots__/PluginLicense-test.tsx.snap | 25 - .../PluginOrganization-test.tsx.snap | 24 - .../PluginRiskConsentBox-test.tsx.snap | 100 ---- .../__snapshots__/PluginUrls-test.tsx.snap | 53 -- .../src/main/js/apps/marketplace/utils.ts | 72 ++- .../src/main/js/helpers/testSelector.ts | 16 +- 44 files changed, 649 insertions(+), 2781 deletions(-) create mode 100644 server/sonar-web/src/main/js/api/mocks/PluginsServiceMock.ts delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/App-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/EditionBoxes-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/Footer-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/Header-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/MarketplaceApp-it.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/MarketplaceAppContainer-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/PluginUpdates-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/PluginsList-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/App-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/EditionBoxes-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/Footer-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/Header-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/MarketplaceAppContainer-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PluginUpdates-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PluginsList-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/EditionBox-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginActions-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginAvailable-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginChangeLog-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginDescription-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginLicense-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginOrganization-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginRiskConsentBox-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginUrls-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginActions-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginAvailable-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginChangeLog-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginDescription-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginLicense-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginOrganization-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginRiskConsentBox-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginUrls-test.tsx.snap diff --git a/server/sonar-web/src/main/js/api/mocks/PluginsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/PluginsServiceMock.ts new file mode 100644 index 00000000000..c5661f16d9e --- /dev/null +++ b/server/sonar-web/src/main/js/api/mocks/PluginsServiceMock.ts @@ -0,0 +1,241 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 { cloneDeep, omit } from 'lodash'; +import { + mockAvailablePlugin, + mockInstalledPlugin, + mockRelease, + mockUpdate, +} from '../../helpers/mocks/plugins'; +import { AvailablePlugin, InstalledPlugin, PendingPluginResult } from '../../types/plugins'; +import { + cancelPendingPlugins, + getAvailablePlugins, + getInstalledPlugins, + getPendingPlugins, + getUpdatesPlugins, + installPlugin, + uninstallPlugin, + updatePlugin, +} from '../plugins'; + +jest.mock('../plugins'); + +const defaultAvailable: AvailablePlugin[] = [ + mockAvailablePlugin({ + key: 'foo', + name: 'CFoo', + category: 'Languages', + description: 'Description', + homepageUrl: 'https://www.sonarsource.com/', + issueTrackerUrl: 'https://www.sonarsource.com/', + organizationName: 'SonarSource', + organizationUrl: 'https://www.sonarsource.com/', + release: mockRelease({ + version: '1.0.0', + description: 'release description', + date: '2020-01-01', + changeLogUrl: 'https://www.sonarsource.com/', + }), + }), + mockAvailablePlugin({ + key: 'bar', + name: 'DTest', + editionBundled: true, + release: mockRelease({ + version: '2.0.0', + }), + }), + mockAvailablePlugin({ + description: 'Mocked Plugin', + termsAndConditionsUrl: 'https://www.sonarsource.com/', + }), +]; +const defaultInstalled: InstalledPlugin[] = [ + mockInstalledPlugin({ + key: 'test', + name: 'ATest_install', + version: '1.1.0', + }), + mockInstalledPlugin({ + key: 'one-update', + name: 'ZTest', + version: '1.1.1', + updates: [ + mockUpdate({ + status: 'COMPATIBLE', + release: mockRelease({ + version: '1.2.0', + date: '2020-01-01', + changeLogUrl: 'https://www.sonarsource.com/', + }), + }), + ], + }), + mockInstalledPlugin({ + key: 'multiple_updates', + name: 'BTest_update', + version: '1.2.0', + editionBundled: true, + updates: [ + mockUpdate({ + status: 'COMPATIBLE', + release: mockRelease({ version: '1.2.1', changeLogUrl: 'https://www.sonarsource.com/' }), + }), + mockUpdate({ + status: 'COMPATIBLE', + release: mockRelease({ version: '1.3.0', changeLogUrl: 'https://www.sonarsource.com/' }), + }), + mockUpdate({ + status: 'NON-COMPATIBLE', + release: mockRelease({ version: '1.4.0', changeLogUrl: 'https://www.sonarsource.com/' }), + }), + ], + }), +]; +const defaultPending: PendingPluginResult = { + installing: [], + removing: [], + updating: [], +}; + +export default class PluginsServiceMock { + #available: AvailablePlugin[]; + #installed: InstalledPlugin[]; + #pending: PendingPluginResult; + + constructor() { + this.#available = cloneDeep(defaultAvailable); + this.#installed = cloneDeep(defaultInstalled); + this.#pending = cloneDeep(defaultPending); + + jest.mocked(getAvailablePlugins).mockImplementation(this.handleGetAvailablePlugins); + jest.mocked(getPendingPlugins).mockImplementation(this.handleGetPendingPlugins); + jest.mocked(getInstalledPlugins).mockImplementation(this.handleGetInstalledPlugins); + jest.mocked(getUpdatesPlugins).mockImplementation(this.handleGetUpdatesPlugins); + jest.mocked(installPlugin).mockImplementation(this.handleInstallPlugin); + jest.mocked(uninstallPlugin).mockImplementation(this.handleUninstallPlugin); + jest.mocked(updatePlugin).mockImplementation(this.handleUpdatePlugin); + jest.mocked(cancelPendingPlugins).mockImplementation(this.handleCancelPendingPlugins); + } + + handleGetAvailablePlugins = () => { + return this.reply({ + plugins: this.#available, + updateCenterRefresh: '2021-01-01T00:00:00+0000', + }); + }; + + handleGetPendingPlugins = () => { + return this.reply(this.#pending); + }; + + handleGetInstalledPlugins = () => { + return this.reply(this.#installed.map((plugin) => omit(plugin, 'updates'))); + }; + + handleGetUpdatesPlugins = () => { + return this.reply({ + plugins: this.#installed + .filter((plugin) => plugin.updates && plugin.updates.length > 0) + .map((plugin) => omit(plugin, 'version', 'updatedAt')), + updateCenterRefresh: '2021-01-01T00:00:00+0000', + }); + }; + + handleGetPluginUpdates = () => { + return this.reply( + this.#installed.filter((plugin) => plugin.updates && plugin.updates.length > 0) + ); + }; + + handleInstallPlugin: typeof installPlugin = (data) => { + const plugin = this.#available.find((plugin) => plugin.key === data.key); + if (plugin === undefined) { + return Promise.reject(new Error('Plugin not found')); + } + this.#pending.installing.push({ + ...omit(plugin, 'release', 'update'), + version: plugin.release.version, + implementationBuild: '20210101-000000', + }); + return this.reply(); + }; + + handleUninstallPlugin: typeof uninstallPlugin = (data) => { + const plugin = this.#installed.find((plugin) => plugin.key === data.key); + if (plugin === undefined) { + return Promise.reject(new Error('Plugin not found')); + } + this.#pending.removing.push({ + ...omit( + plugin, + 'updates', + 'updatedAt', + 'sonarLintSupported', + 'hash', + 'filename', + 'documentationPath' + ), + implementationBuild: '20210101-000000', + }); + return this.reply(); + }; + + handleUpdatePlugin: typeof updatePlugin = (data) => { + const plugin = this.#installed + .filter((plugin) => plugin.updates && plugin.updates.length > 0) + .find((plugin) => plugin.key === data.key); + if (plugin === undefined || plugin.updates === undefined || plugin.updates.length === 0) { + return Promise.reject(new Error('Plugin not found')); + } + this.#pending.updating.push({ + ...omit( + plugin, + 'updates', + 'updatedAt', + 'sonarLintSupported', + 'hash', + 'filename', + 'documentationPath' + ), + version: plugin.updates[plugin.updates.length - 1].release?.version ?? '', + implementationBuild: '20210101-000000', + }); + return this.reply(); + }; + + handleCancelPendingPlugins: typeof cancelPendingPlugins = () => { + this.#pending = cloneDeep(defaultPending); + return this.reply(); + }; + + reset = () => { + this.#available = cloneDeep(defaultAvailable); + this.#installed = cloneDeep(defaultInstalled); + this.#pending = cloneDeep(defaultPending); + }; + + reply(): Promise; + reply(response: T): Promise; + reply(response?: T): Promise { + return Promise.resolve(response ? cloneDeep(response) : undefined); + } +} diff --git a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts index aefca24cfd0..41ff5481689 100644 --- a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts @@ -38,6 +38,7 @@ import { getValues, resetSettingValue, setSettingValue, + setSimpleSettingValue, } from '../settings'; jest.mock('../settings'); @@ -126,6 +127,7 @@ export default class SettingsServiceMock { jest.mocked(getValues).mockImplementation(this.handleGetValues); jest.mocked(getAllValues).mockImplementation(this.handleGetAllValues); jest.mocked(setSettingValue).mockImplementation(this.handleSetSettingValue); + jest.mocked(setSimpleSettingValue).mockImplementation(this.handleSetSimpleSettingValue); jest.mocked(resetSettingValue).mockImplementation(this.handleResetSettingValue); jest.mocked(checkSecretKey).mockImplementation(this.handleCheckSecretKey); jest.mocked(generateSecretKey).mockImplementation(this.handleGenerateSecretKey); @@ -219,6 +221,11 @@ export default class SettingsServiceMock { return this.reply({ encryptedValue: 'encryptedValue' }); }; + handleSetSimpleSettingValue: typeof setSimpleSettingValue = (data) => { + this.set(data.key, data.value); + return this.reply(undefined); + }; + setSecretKeyAvailable = (val = false) => { this.#secretKeyAvailable = val; }; diff --git a/server/sonar-web/src/main/js/api/plugins.ts b/server/sonar-web/src/main/js/api/plugins.ts index c970c2c3d56..8321da4fb6b 100644 --- a/server/sonar-web/src/main/js/api/plugins.ts +++ b/server/sonar-web/src/main/js/api/plugins.ts @@ -17,16 +17,13 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { findLastIndex } from 'lodash'; import { throwGlobalError } from '../helpers/error'; import { getJSON, post } from '../helpers/request'; -import { isDefined } from '../helpers/types'; import { AvailablePlugin, InstalledPlugin, PendingPluginResult, PluginType, - Update, } from '../types/plugins'; export function getAvailablePlugins(): Promise<{ @@ -40,85 +37,17 @@ export function getPendingPlugins(): Promise { return getJSON('/api/plugins/pending').catch(throwGlobalError); } -function getLastUpdates(updates: undefined | Update[]): Update[] { - if (!updates) { - return []; - } - const lastUpdate = ['COMPATIBLE', 'REQUIRES_SYSTEM_UPGRADE', 'DEPS_REQUIRE_SYSTEM_UPGRADE'].map( - (status) => { - const index = findLastIndex(updates, (update) => update.status === status); - return index > -1 ? updates[index] : undefined; - } +export function getInstalledPlugins(type = PluginType.External): Promise { + return getJSON('/api/plugins/installed', { f: 'category', type }).then( + ({ plugins }) => plugins, + throwGlobalError ); - return lastUpdate.filter(isDefined); } -function addChangelog(update: Update, updates?: Update[]) { - if (!updates) { - return update; - } - const index = updates.indexOf(update); - const previousUpdates = index > 0 ? updates.slice(0, index) : []; - return { ...update, previousUpdates }; -} - -function getInstalledPluginApi(type = PluginType.External) { - return getJSON('/api/plugins/installed', { f: 'category', type }); -} - -function getUpdatesPluginApi() { +export function getUpdatesPlugins() { return getJSON('/api/plugins/updates'); } -export function getInstalledPlugins( - type: PluginType = PluginType.External -): Promise { - return getInstalledPluginApi(type).then(({ plugins }) => plugins, throwGlobalError); -} - -export function getInstalledPluginsWithUpdates(): Promise { - return Promise.all([getInstalledPluginApi(), getUpdatesPluginApi()]) - .then(([installed, updates]) => - installed.plugins.map((plugin: InstalledPlugin) => { - const updatePlugin: InstalledPlugin = updates.plugins.find( - (p: InstalledPlugin) => p.key === plugin.key - ); - if (updatePlugin) { - return { - ...updatePlugin, - ...plugin, - updates: getLastUpdates(updatePlugin.updates).map((update) => - addChangelog(update, updatePlugin.updates) - ), - }; - } - return plugin; - }) - ) - .catch(throwGlobalError); -} - -export function getPluginUpdates(): Promise { - return Promise.all([getUpdatesPluginApi(), getInstalledPluginApi()]) - .then(([updates, installed]) => - updates.plugins.map((updatePlugin: InstalledPlugin) => { - const updates = getLastUpdates(updatePlugin.updates).map((update) => - addChangelog(update, updatePlugin.updates) - ); - const plugin = installed.plugins.find((p: InstalledPlugin) => p.key === updatePlugin.key); - if (plugin) { - return { - ...plugin, - ...updatePlugin, - updates, - }; - } - return { ...updatePlugin, updates }; - }) - ) - .catch(throwGlobalError); -} - export function installPlugin(data: { key: string }): Promise { return post('/api/plugins/install', data).catch(throwGlobalError); } diff --git a/server/sonar-web/src/main/js/apps/marketplace/App.tsx b/server/sonar-web/src/main/js/apps/marketplace/App.tsx index 52dd3a65eeb..9b5afe83d71 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/App.tsx +++ b/server/sonar-web/src/main/js/apps/marketplace/App.tsx @@ -21,12 +21,7 @@ import { sortBy, uniqBy } from 'lodash'; import * as React from 'react'; import { Helmet } from 'react-helmet-async'; import { FormattedMessage } from 'react-intl'; -import { - getAvailablePlugins, - getInstalledPlugins, - getInstalledPluginsWithUpdates, - getPluginUpdates, -} from '../../api/plugins'; +import { getAvailablePlugins, getInstalledPlugins } from '../../api/plugins'; import { getValue, setSimpleSettingValue } from '../../api/settings'; import DocLink from '../../components/common/DocLink'; import Suggestions from '../../components/embed-docs-modal/Suggestions'; @@ -37,14 +32,21 @@ import { translate } from '../../helpers/l10n'; import { EditionKey } from '../../types/editions'; import { PendingPluginResult, Plugin, RiskConsent } from '../../types/plugins'; import { SettingsKey } from '../../types/settings'; -import PluginRiskConsentBox from './components/PluginRiskConsentBox'; import EditionBoxes from './EditionBoxes'; import Footer from './Footer'; import Header from './Header'; import PluginsList from './PluginsList'; import Search from './Search'; +import PluginRiskConsentBox from './components/PluginRiskConsentBox'; import './style.css'; -import { filterPlugins, parseQuery, Query, serializeQuery } from './utils'; +import { + Query, + filterPlugins, + getInstalledPluginsWithUpdates, + getPluginUpdates, + parseQuery, + serializeQuery, +} from './utils'; interface Props { currentEdition?: EditionKey; @@ -62,7 +64,7 @@ interface State { riskConsent?: RiskConsent; } -export class App extends React.PureComponent { +class App extends React.PureComponent { mounted = false; state: State = { loadingPlugins: true, plugins: [] }; diff --git a/server/sonar-web/src/main/js/apps/marketplace/MarketplaceAppContainer.tsx b/server/sonar-web/src/main/js/apps/marketplace/MarketplaceAppContainer.tsx index df1d0f33ba0..687a2986165 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/MarketplaceAppContainer.tsx +++ b/server/sonar-web/src/main/js/apps/marketplace/MarketplaceAppContainer.tsx @@ -31,7 +31,7 @@ export interface MarketplaceAppContainerProps { appState: AppState; } -export function MarketplaceAppContainer(props: MarketplaceAppContainerProps) { +function MarketplaceAppContainer(props: MarketplaceAppContainerProps) { const { appState, location } = props; const propsToPass = { diff --git a/server/sonar-web/src/main/js/apps/marketplace/PluginsList.tsx b/server/sonar-web/src/main/js/apps/marketplace/PluginsList.tsx index a8e7021147c..d1f094941df 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/PluginsList.tsx +++ b/server/sonar-web/src/main/js/apps/marketplace/PluginsList.tsx @@ -19,6 +19,7 @@ */ import { sortBy } from 'lodash'; import * as React from 'react'; +import { translate } from '../../helpers/l10n'; import { isAvailablePlugin, isInstalledPlugin, PendingPlugin, Plugin } from '../../types/plugins'; import PluginAvailable from './components/PluginAvailable'; import PluginInstalled from './components/PluginInstalled'; @@ -53,7 +54,7 @@ export default function PluginsList(props: PluginsListProps) { const installedPlugins = plugins.filter(isInstalledPlugin); return (
-
    +
      {sortBy(plugins, ({ name }) => name).map((plugin) => (
    • diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/__tests__/App-test.tsx deleted file mode 100644 index a55d327f73c..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/App-test.tsx +++ /dev/null @@ -1,118 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { - getAvailablePlugins, - getInstalledPlugins, - getInstalledPluginsWithUpdates, - getPluginUpdates, -} from '../../../api/plugins'; -import { getValue, setSimpleSettingValue } from '../../../api/settings'; -import { mockLocation, mockRouter } from '../../../helpers/testMocks'; -import { waitAndUpdate } from '../../../helpers/testUtils'; -import { EditionKey } from '../../../types/editions'; -import { RiskConsent } from '../../../types/plugins'; -import { SettingsKey } from '../../../types/settings'; -import { App } from '../App'; - -jest.mock('../../../api/plugins', () => { - const plugin = jest.requireActual('../../../helpers/mocks/plugins').mockPlugin(); - - return { - getAvailablePlugins: jest.fn().mockResolvedValue({ plugins: [plugin] }), - getInstalledPlugins: jest.fn().mockResolvedValue([]), - getInstalledPluginsWithUpdates: jest.fn().mockResolvedValue([]), - getPluginUpdates: jest.fn().mockResolvedValue([]), - }; -}); - -jest.mock('../../../api/settings', () => ({ - getValue: jest.fn().mockResolvedValue({}), - setSimpleSettingValue: jest.fn().mockResolvedValue(true), -})); - -beforeEach(jest.clearAllMocks); - -it('should render correctly', async () => { - const wrapper = shallowRender(); - expect(wrapper).toMatchSnapshot('loading'); - - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot('loaded'); - - wrapper.setProps({ currentEdition: EditionKey.community, standaloneMode: true }); - wrapper.setState({ riskConsent: RiskConsent.Accepted }); - - expect(wrapper).toMatchSnapshot('not readonly'); -}); - -it('should handle accepting the risk', async () => { - (getValue as jest.Mock) - .mockResolvedValueOnce({ value: RiskConsent.NotAccepted }) - .mockResolvedValueOnce({ value: RiskConsent.Accepted }); - - const wrapper = shallowRender(); - - await waitAndUpdate(wrapper); - expect(getValue).toHaveBeenCalledWith({ key: SettingsKey.PluginRiskConsent }); - - wrapper.instance().acknowledgeRisk(); - - await new Promise(setImmediate); - - expect(setSimpleSettingValue).toHaveBeenCalled(); - expect(getValue).toHaveBeenCalledWith({ key: SettingsKey.PluginRiskConsent }); - expect(wrapper.state().riskConsent).toBe(RiskConsent.Accepted); -}); - -it('should fetch plugin info', async () => { - const wrapper = shallowRender(); - - await waitAndUpdate(wrapper); - expect(getInstalledPluginsWithUpdates).toHaveBeenCalled(); - expect(getAvailablePlugins).toHaveBeenCalled(); - - wrapper.setProps({ location: mockLocation({ query: { filter: 'updates' } }) }); - await waitAndUpdate(wrapper); - expect(getPluginUpdates).toHaveBeenCalled(); - - wrapper.setProps({ location: mockLocation({ query: { filter: 'installed' } }) }); - await waitAndUpdate(wrapper); - expect(getInstalledPlugins).toHaveBeenCalled(); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/EditionBoxes-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/__tests__/EditionBoxes-test.tsx deleted file mode 100644 index 7c6b8b9c4d1..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/EditionBoxes-test.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { EditionKey } from '../../../types/editions'; -import EditionBoxes from '../EditionBoxes'; - -jest.mock('../../../api/navigation', () => ({ - getMarketplaceNavigation: jest.fn().mockResolvedValue({}), -})); - -it('should display the available edition boxes correctly', () => { - expect(getWrapper()).toMatchSnapshot(); -}); - -it('should display the enterprise and datacenter edition boxes', () => { - expect(getWrapper({ currentEdition: EditionKey.developer })).toMatchSnapshot(); -}); - -it('should display the datacenter edition box only', () => { - expect(getWrapper({ currentEdition: EditionKey.enterprise })).toMatchSnapshot(); -}); - -it('should not display any edition box', () => { - expect(getWrapper({ currentEdition: EditionKey.datacenter }).type()).toBeNull(); -}); - -function getWrapper(props = {}) { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/Footer-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/__tests__/Footer-test.tsx deleted file mode 100644 index 04b0823362a..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/Footer-test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 Footer from '../Footer'; - -it('should display the number of plugins', () => { - expect(shallow(
      )).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/Header-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/__tests__/Header-test.tsx deleted file mode 100644 index 88245a6bc14..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/Header-test.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { EditionKey } from '../../../types/editions'; -import Header from '../Header'; - -it('should render with installed editions', () => { - expect(shallow(
      )).toMatchSnapshot(); - expect(shallow(
      )).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/MarketplaceApp-it.tsx b/server/sonar-web/src/main/js/apps/marketplace/__tests__/MarketplaceApp-it.tsx new file mode 100644 index 00000000000..a1302a952ee --- /dev/null +++ b/server/sonar-web/src/main/js/apps/marketplace/__tests__/MarketplaceApp-it.tsx @@ -0,0 +1,279 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 { act } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React, { useState } from 'react'; +import { NavigationServiceMock } from '../../../api/mocks/NavigationServiceMock'; +import PluginsServiceMock from '../../../api/mocks/PluginsServiceMock'; +import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock'; +import AdminContext from '../../../app/components/AdminContext'; +import { mockAppState } from '../../../helpers/testMocks'; +import { renderApp } from '../../../helpers/testReactTestingUtils'; +import { byRole, byText } from '../../../helpers/testSelector'; +import { AppState } from '../../../types/appstate'; +import { EditionKey } from '../../../types/editions'; +import { PendingPluginResult } from '../../../types/plugins'; +import { GlobalSettingKeys } from '../../../types/settings'; +import MarketplaceAppContainer from '../MarketplaceAppContainer'; + +const handler = new PluginsServiceMock(); +const settingsHandler = new SettingsServiceMock(); +const navigationHandler = new NavigationServiceMock(); + +const ui = { + title: byRole('heading', { name: 'marketplace.page.plugins' }), + deTitle: byRole('heading', { name: 'SonarQube logo Developer Edition' }), + eeTitle: byRole('heading', { name: 'SonarQube logo Enterprise Edition' }), + dceTitle: byRole('heading', { name: 'SonarQube logo Data Center Edition' }), + pluginRow: byRole('list', { name: 'marketplace.page.plugins' }).byRole('table'), + filterAll: byRole('button', { name: 'marketplace.all' }), + filterInstalled: byRole('button', { name: 'marketplace.installed' }), + filterWithUpdates: byRole('button', { name: 'marketplace.updates_only' }), + search: byRole('searchbox', { name: 'marketplace.search' }), + clearSearch: byRole('button', { name: 'clear' }), + noPluginsText: byText('marketplace.plugin_list.no_plugins', { exact: false }), + acceptTerms: byRole('checkbox', { name: 'marketplace.i_accept_the' }), + installButton: byRole('button', { name: 'marketplace.install' }), + uninstallButton: byRole('button', { name: 'marketplace.uninstall' }), + updateButton: byRole('button', { name: /marketplace.update_to_x/ }), + installPending: byText('marketplace.install_pending'), + uninstallPending: byText('marketplace.uninstall_pending'), + updatePending: byText('marketplace.update_pending'), + riskConsentMessage: byText('marketplace.risk_consent.installation'), + riskConsentButton: byRole('button', { name: 'marketplace.risk_consent.action' }), + releaseDetailsButton: byRole('button', { name: /marketplace.show_plugin_changelog/ }), + homePageLink: byRole('link', { name: 'marketplace.homepage' }), + issueTrackerLink: byRole('link', { name: 'marketplace.issue_tracker' }), + releaseNotesLink: byRole('link', { name: 'marketplace.release_notes' }), + organizationLink: byRole('link', { name: 'SonarSource' }), + bundledAvailable: byText('marketplace.available_under_commercial_license'), +}; + +beforeEach(() => { + handler.reset(); + settingsHandler.reset(); + navigationHandler.reset(); +}); + +it('should show editions', async () => { + renderMarketplaceApp(); + expect(await ui.title.find()).toBeInTheDocument(); + expect(ui.deTitle.get()).toBeInTheDocument(); + expect(ui.eeTitle.get()).toBeInTheDocument(); + expect(ui.dceTitle.get()).toBeInTheDocument(); +}); + +it('should show and filter the list', async () => { + renderMarketplaceApp(); + expect(await ui.pluginRow.findAll()).toHaveLength(6); + expect(ui.filterAll.get()).toHaveAttribute('aria-current', 'true'); + await userEvent.click(ui.filterInstalled.get()); + expect(await ui.pluginRow.findAll()).toHaveLength(3); + await userEvent.click(ui.filterWithUpdates.get()); + expect(await ui.pluginRow.findAll()).toHaveLength(2); + await userEvent.click(ui.filterAll.get()); + expect(await ui.pluginRow.findAll()).toHaveLength(6); + await userEvent.type(ui.search.get(), 'Mocked Plugin'); + expect(await ui.pluginRow.findAll()).toHaveLength(1); + await userEvent.clear(ui.search.get()); + expect(await ui.pluginRow.findAll()).toHaveLength(6); + await userEvent.type(ui.search.get(), 'Test'); + expect(await ui.pluginRow.findAll()).toHaveLength(4); + await userEvent.clear(ui.search.get()); + await userEvent.type(ui.search.get(), 'Languages'); + expect(await ui.pluginRow.findAll()).toHaveLength(1); + await userEvent.clear(ui.search.get()); + await userEvent.type(ui.search.get(), 'cantfindtheplugin'); + expect(ui.pluginRow.query()).not.toBeInTheDocument(); + expect(ui.noPluginsText.get()).toBeInTheDocument(); +}); + +it('should install, uninstall, update', async () => { + const user = userEvent.setup(); + renderMarketplaceApp(); + const rows = await ui.pluginRow.findAll(); + expect(rows).toHaveLength(6); + expect(ui.installButton.query()).not.toBeInTheDocument(); + expect(ui.uninstallButton.query()).not.toBeInTheDocument(); + expect(ui.updateButton.query()).not.toBeInTheDocument(); + expect(ui.riskConsentMessage.get()).toBeInTheDocument(); + expect(ui.riskConsentButton.get()).toBeInTheDocument(); + await act(() => user.click(ui.riskConsentButton.get())); + expect(ui.riskConsentMessage.query()).not.toBeInTheDocument(); + + expect(rows[0]).toHaveTextContent('ATest_install'); + expect(await ui.uninstallButton.find(rows[0])).toBeInTheDocument(); + expect(ui.installButton.query(rows[0])).not.toBeInTheDocument(); + expect(ui.updateButton.query(rows[0])).not.toBeInTheDocument(); + expect(ui.uninstallPending.query(rows[0])).not.toBeInTheDocument(); + await act(() => user.click(ui.uninstallButton.get(rows[0]))); + expect(await ui.uninstallPending.find(rows[0])).toBeInTheDocument(); + expect(ui.uninstallButton.query(rows[0])).not.toBeInTheDocument(); + + expect(rows[1]).toHaveTextContent('BTest_update'); + expect(ui.installButton.query(rows[1])).not.toBeInTheDocument(); + expect(ui.uninstallButton.query(rows[1])).not.toBeInTheDocument(); + expect(ui.updateButton.get(rows[1])).toBeInTheDocument(); + expect(ui.updateButton.get(rows[1])).toHaveTextContent('1.3.0'); + expect(ui.updatePending.query(rows[1])).not.toBeInTheDocument(); + await act(() => user.click(ui.updateButton.get(rows[1]))); + expect(await ui.updatePending.find(rows[1])).toBeInTheDocument(); + expect(ui.updateButton.query(rows[1])).not.toBeInTheDocument(); + + expect(rows[2]).toHaveTextContent('CFoo'); + expect(ui.installButton.get(rows[2])).toBeInTheDocument(); + expect(ui.uninstallButton.query(rows[2])).not.toBeInTheDocument(); + expect(ui.updateButton.query(rows[2])).not.toBeInTheDocument(); + expect(ui.installPending.query(rows[2])).not.toBeInTheDocument(); + await act(() => user.click(ui.installButton.get(rows[2]))); + expect(await ui.installPending.find(rows[2])).toBeInTheDocument(); + expect(ui.installButton.query(rows[2])).not.toBeInTheDocument(); + + expect(rows[3]).toHaveTextContent('DTest'); + expect(ui.installButton.query(rows[2])).not.toBeInTheDocument(); + expect(ui.bundledAvailable.get(rows[3])).toBeInTheDocument(); + + expect(rows[4]).toHaveTextContent('Sonar Foo'); + expect(ui.installButton.get(rows[4])).toBeInTheDocument(); + expect(ui.installButton.get(rows[4])).toBeDisabled(); + expect(ui.acceptTerms.get(rows[4])).toBeInTheDocument(); + expect(ui.acceptTerms.get(rows[4])).not.toBeChecked(); + await user.click(ui.acceptTerms.get(rows[4])); + expect(ui.installButton.get(rows[4])).toBeEnabled(); + await act(() => user.click(ui.installButton.get(rows[4]))); + expect(await ui.installPending.find(rows[4])).toBeInTheDocument(); + expect(ui.installButton.query(rows[4])).not.toBeInTheDocument(); + + expect(rows[5]).toHaveTextContent('ZTest'); + expect(ui.installButton.query(rows[5])).not.toBeInTheDocument(); + expect(ui.uninstallButton.query(rows[5])).toBeInTheDocument(); + expect(ui.updateButton.get(rows[5])).toBeInTheDocument(); + expect(ui.updateButton.get(rows[5])).toHaveTextContent('1.2.0'); + expect(ui.updatePending.query(rows[5])).not.toBeInTheDocument(); + await act(() => user.click(ui.updateButton.get(rows[5]))); + expect(await ui.updatePending.find(rows[5])).toBeInTheDocument(); + expect(ui.uninstallButton.query(rows[5])).not.toBeInTheDocument(); + expect(ui.updateButton.query(rows[5])).not.toBeInTheDocument(); +}); + +it('should show details on the row', async () => { + const user = userEvent.setup(); + renderMarketplaceApp(); + const rows = await ui.pluginRow.findAll(); + const row = rows[2]; + expect(row).toHaveTextContent('CFooLanguagesDescription1.0.0release description'); + expect(ui.homePageLink.get(row)).toBeInTheDocument(); + expect(ui.issueTrackerLink.get(row)).toBeInTheDocument(); + expect(ui.organizationLink.get(row)).toBeInTheDocument(); + expect(ui.releaseDetailsButton.get(row)).toBeInTheDocument(); + expect(ui.releaseNotesLink.query(row)).not.toBeInTheDocument(); + await user.click(ui.releaseDetailsButton.get(row)); + expect(ui.releaseNotesLink.get(row)).toBeInTheDocument(); + + expect(ui.homePageLink.query(rows[0])).not.toBeInTheDocument(); + expect(ui.issueTrackerLink.query(rows[0])).not.toBeInTheDocument(); + expect(ui.organizationLink.query(rows[0])).not.toBeInTheDocument(); + + const rowWithMultipleUpdates = rows[1]; + expect(rowWithMultipleUpdates).toHaveTextContent( + '1.2.0marketplace._installedmarketplace.updates:1.3.0' + ); + await user.click(ui.releaseDetailsButton.get(rowWithMultipleUpdates)); + expect(ui.releaseNotesLink.getAll(rowWithMultipleUpdates)).toHaveLength(2); +}); + +it.each([ + [EditionKey.developer, { de: false, ee: true, dce: true }], + [EditionKey.enterprise, { de: false, ee: false, dce: true }], + [EditionKey.datacenter, { de: false, ee: false, dce: false }], +])( + 'should not allow installations on editions higher than community', + async (edition, showTitles) => { + renderMarketplaceApp({ edition }); + const rows = await ui.pluginRow.findAll(); + expect(rows).toHaveLength(6); + expect(ui.updateButton.query()).not.toBeInTheDocument(); + expect(ui.installButton.query()).not.toBeInTheDocument(); + expect(ui.uninstallButton.query()).not.toBeInTheDocument(); + + Object.entries(showTitles).forEach( + ([key, value]: [key: 'de' | 'ee' | 'dce', value: boolean]) => { + // eslint-disable-next-line jest/no-conditional-in-test + if (value) { + // eslint-disable-next-line jest/no-conditional-expect + expect(ui[`${key}Title`].get()).toBeInTheDocument(); + } else { + // eslint-disable-next-line jest/no-conditional-expect + expect(ui[`${key}Title`].query()).not.toBeInTheDocument(); + } + } + ); + + expect(ui.riskConsentMessage.query()).not.toBeInTheDocument(); + } +); + +describe('accessibility', () => { + it('should be accessible', async () => { + const user = userEvent.setup(); + renderMarketplaceApp(); + const row = (await ui.pluginRow.findAll())[1]; + await expect(document.body).toHaveNoA11yViolations(); + await act(() => user.click(ui.riskConsentButton.get())); + await act(() => user.click(ui.releaseDetailsButton.get(row))); + await expect(document.body).toHaveNoA11yViolations(); + }); +}); + +function renderMarketplaceApp(appStateOverrides: Partial = {}) { + function Wrapper() { + const [pendingPlugins, setPendingPlugins] = useState({ + installing: [], + removing: [], + updating: [], + }); + const fetchPendingPlugins = async () => { + setPendingPlugins(await handler.handleGetPendingPlugins()); + }; + return ( + {}, + fetchPendingPlugins, + pendingPlugins, + systemStatus: null as any, + }} + > + + + ); + } + + return renderApp('admin/marketplace', , { + appState: mockAppState({ + edition: EditionKey.community, + standalone: true, + settings: { + [GlobalSettingKeys.UpdatecenterActivated]: 'true', + }, + ...appStateOverrides, + }), + }); +} diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/MarketplaceAppContainer-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/__tests__/MarketplaceAppContainer-test.tsx deleted file mode 100644 index e923c23f9be..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/MarketplaceAppContainer-test.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 React from 'react'; -import { mockAppState, mockLocation } from '../../../helpers/testMocks'; -import { GlobalSettingKeys } from '../../../types/settings'; -import { EditionKey } from '../../../types/editions'; -import { MarketplaceAppContainer, MarketplaceAppContainerProps } from '../MarketplaceAppContainer'; - -it('should render correctly', () => { - expect(shallowRender().dive()).toMatchSnapshot('default'); - expect( - shallowRender({ - appState: mockAppState({ - settings: { - [GlobalSettingKeys.UpdatecenterActivated]: 'true', - }, - }), - }).dive() - ).toMatchSnapshot('update center active'); -}); - -function shallowRender(overrides: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/PluginUpdates-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/__tests__/PluginUpdates-test.tsx deleted file mode 100644 index 7f9cf9c1d0d..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/PluginUpdates-test.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 PluginUpdates, { PluginUpdatesProps } from '../components/PluginUpdates'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('default'); - expect( - shallowRender({ - updates: [ - { - requires: [], - status: '', - release: { date: '2012-02-10', version: '1.3' }, - }, - { - requires: [], - status: '', - release: { date: '2012-02-01', version: '1.1' }, - }, - { - requires: [], - status: '', - release: { date: '2012-02-02', version: '1.2' }, - }, - ], - }) - ).toMatchSnapshot('with status'); -}); - -function shallowRender(props: Partial = {}) { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/PluginsList-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/__tests__/PluginsList-test.tsx deleted file mode 100644 index 4046e2fbd0b..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/PluginsList-test.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { mockAvailablePlugin, mockPendingPlugin } from '../../../helpers/mocks/plugins'; -import PluginsList, { PluginsListProps } from '../PluginsList'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('default'); - expect( - shallowRender({ - pending: { - installing: [mockPendingPlugin({ key: 'sonar-foo' })], - updating: [mockPendingPlugin({ key: 'sonar-bar' })], - removing: [mockPendingPlugin({ key: 'sonar-baz' })], - }, - }) - ).toMatchSnapshot('with status'); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/App-test.tsx.snap deleted file mode 100644 index dddad9f865d..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/App-test.tsx.snap +++ /dev/null @@ -1,254 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: loaded 1`] = ` -
      - - -
      - -
      -

      - marketplace.page.plugins -

      -
      -

      - marketplace.page.plugins.description -

      - - - marketplace.page.plugins.description2.link - , - } - } - /> - -
      -
      - - - - -
      - -
      -`; - -exports[`should render correctly: loading 1`] = ` -
      - - -
      - -
      -

      - marketplace.page.plugins -

      -
      -

      - marketplace.page.plugins.description -

      - - - marketplace.page.plugins.description2.link - , - } - } - /> - -
      -
      - - - - marketplace.plugin_list.no_plugins.all - -
      -`; - -exports[`should render correctly: not readonly 1`] = ` -
      - - -
      - -
      -

      - marketplace.page.plugins -

      -
      -

      - marketplace.page.plugins.description -

      -
      -
      - - - - -
      - -
      -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/EditionBoxes-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/EditionBoxes-test.tsx.snap deleted file mode 100644 index 9e68295f6e4..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/EditionBoxes-test.tsx.snap +++ /dev/null @@ -1,94 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display the available edition boxes correctly 1`] = ` -
      - - - -
      -`; - -exports[`should display the datacenter edition box only 1`] = ` -
      - -
      -`; - -exports[`should display the enterprise and datacenter edition boxes 1`] = ` -
      - - -
      -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/Footer-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/Footer-test.tsx.snap deleted file mode 100644 index 164d3bd00e6..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/Footer-test.tsx.snap +++ /dev/null @@ -1,9 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display the number of plugins 1`] = ` -
      - x_show.3 -
      -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/Header-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/Header-test.tsx.snap deleted file mode 100644 index 83e8c3b7b33..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/Header-test.tsx.snap +++ /dev/null @@ -1,47 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render with installed editions 1`] = ` -
      -

      - marketplace.page -

      -

      - marketplace.page.you_are_running.community -

      -

      - marketplace.page.description -

      -
      -`; - -exports[`should render with installed editions 2`] = ` -
      -

      - marketplace.page -

      -

      - marketplace.page.you_are_running.datacenter -

      -

      - marketplace.page.description_best_edition -

      -
      -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/MarketplaceAppContainer-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/MarketplaceAppContainer-test.tsx.snap deleted file mode 100644 index 6a51a26919c..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/MarketplaceAppContainer-test.tsx.snap +++ /dev/null @@ -1,52 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = ` - -`; - -exports[`should render correctly: update center active 1`] = ` - -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PluginUpdates-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PluginUpdates-test.tsx.snap deleted file mode 100644 index a23a7b78f58..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PluginUpdates-test.tsx.snap +++ /dev/null @@ -1,78 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = `""`; - -exports[`should render correctly: with status 1`] = ` -
    • - - marketplace.updates - : - -
        - - - -
      -
    • -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PluginsList-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PluginsList-test.tsx.snap deleted file mode 100644 index b7e62907a75..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PluginsList-test.tsx.snap +++ /dev/null @@ -1,204 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = ` -
      -
        -
      • -
      - - - -
      -
    • -
    • - - - - -
      -
    • -
    • - - - - -
      -
    • -
    -
-`; - -exports[`should render correctly: with status 1`] = ` -
-
    -
  • - - - - -
    -
  • -
  • - - - - -
    -
  • -
  • - - - - -
    -
  • -
-
-`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/PluginActions.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/PluginActions.tsx index 487b50dabe1..aff28bf3c4f 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/components/PluginActions.tsx +++ b/server/sonar-web/src/main/js/apps/marketplace/components/PluginActions.tsx @@ -122,7 +122,7 @@ export default class PluginActions extends React.PureComponent { return (
{isAvailablePlugin(plugin) && plugin.termsAndConditionsUrl && ( -

+

{ > {translate('marketplace.terms_and_conditions')} -

+
)} {loading && } {isInstalledPlugin(plugin) && ( diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/PluginChangeLog.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/PluginChangeLog.tsx index 4354d987118..0c0296256df 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/components/PluginChangeLog.tsx +++ b/server/sonar-web/src/main/js/apps/marketplace/components/PluginChangeLog.tsx @@ -31,7 +31,7 @@ export interface Props { export default function PluginChangeLog({ release, update }: Props) { return (
-
{translate('changelog')}
+ {translate('changelog')}
    {update.previousUpdates && sortBy(update.previousUpdates, (prevUpdate) => prevUpdate.release?.date).map( diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/PluginUpdateItem.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/PluginUpdateItem.tsx index d8e50710ab6..4ba13f54729 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/components/PluginUpdateItem.tsx +++ b/server/sonar-web/src/main/js/apps/marketplace/components/PluginUpdateItem.tsx @@ -29,49 +29,22 @@ interface Props { release: Release; } -interface State { - changelogOpen: boolean; -} - -export default class PluginUpdateItem extends React.PureComponent { - state: State = { changelogOpen: false }; - - handleChangelogClick = (event: React.SyntheticEvent) => { - event.preventDefault(); - event.stopPropagation(); - this.toggleChangelog(); - }; - - toggleChangelog = (show?: boolean) => { - if (show !== undefined) { - this.setState({ changelogOpen: show }); - } else { - this.setState((state) => ({ changelogOpen: !state.changelogOpen })); - } - }; - - render() { - const { release, update } = this.props; - return ( -
  • -
    - {update.status === 'COMPATIBLE' ? ( - {release.version} - ) : ( - - {release.version} - - )} -
    -
    - {release.description} - -
    -
  • - ); - } +export default function PluginUpdateItem({ release, update, pluginName }: Props) { + return ( +
  • +
    + {update.status === 'COMPATIBLE' ? ( + {release.version} + ) : ( + + {release.version} + + )} +
    +
    + {release.description} + +
    +
  • + ); } diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/EditionBox-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/EditionBox-test.tsx deleted file mode 100644 index 037d0606860..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/EditionBox-test.tsx +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { getEdition } from '../../../../helpers/editions'; -import { EditionKey } from '../../../../types/editions'; -import EditionBox from '../EditionBox'; - -it('should display the edition', () => { - expect( - shallow( - - ) - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginActions-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginActions-test.tsx deleted file mode 100644 index 37fab4d8e0c..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginActions-test.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { AvailablePlugin, InstalledPlugin } from '../../../../types/plugins'; -import PluginActions from '../PluginActions'; - -const installedPlugin: InstalledPlugin = { - key: 'foo', - name: 'Foo', - filename: 'foo.zip', - hash: '', - implementationBuild: '', - sonarLintSupported: true, - termsAndConditionsUrl: 'https://url', - updatedAt: 1, - updates: [{ status: 'COMPATIBLE', requires: [] }], - version: '7.7', -}; - -const availablePlugin: AvailablePlugin = { - key: 'foo', - name: 'Foo', - release: { version: '7.7', date: 'date' }, - termsAndConditionsUrl: 'https://url', - update: { status: 'COMPATIBLE', requires: [] }, -}; - -it('should render installed plugin correctly', () => { - expect(shallowRender()).toMatchSnapshot(); - expect(shallowRender({ plugin: { ...installedPlugin, editionBundled: true } })).toMatchSnapshot(); -}); - -it('should render available plugin correctly', () => { - expect(shallowRender({ plugin: availablePlugin })).toMatchSnapshot(); - expect(shallowRender({ plugin: { ...availablePlugin, editionBundled: true } })).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginAvailable-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginAvailable-test.tsx deleted file mode 100644 index b0e18d39052..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginAvailable-test.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { - mockAvailablePlugin, - mockInstalledPlugin, - mockPlugin, - mockUpdate, -} from '../../../../helpers/mocks/plugins'; -import PluginAvailable, { PluginAvailableProps } from '../PluginAvailable'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('default'); - expect(shallowRender({ readOnly: true })).toMatchSnapshot('read only'); - expect( - shallowRender({ - plugin: mockAvailablePlugin({ - update: mockUpdate({ requires: [mockPlugin()] }), - }), - }) - ).toMatchSnapshot('has requirements'); - const installed = mockInstalledPlugin({ key: 'sonar-bar', name: 'Sonar Bar' }); - expect( - shallowRender({ - installedPlugins: [installed], - plugin: mockAvailablePlugin({ - update: mockUpdate({ - requires: [mockPlugin(), installed], - }), - }), - }) - ).toMatchSnapshot('has requirements, some of them already met'); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginChangeLog-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginChangeLog-test.tsx deleted file mode 100644 index a3175a05368..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginChangeLog-test.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 PluginChangeLog, { Props } from '../PluginChangeLog'; - -it('should render correctly', () => { - const wrapper = shallowRender(); - expect(wrapper).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginDescription-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginDescription-test.tsx deleted file mode 100644 index 42192e3bc3c..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginDescription-test.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 PluginDescription from '../PluginDescription'; - -it('should display the description and category', () => { - expect(getWrapper()).toMatchSnapshot(); -}); - -it('should not display any category', () => { - expect( - getWrapper({ plugin: { key: 'foo', name: 'Foo', description: 'foo description' } }) - ).toMatchSnapshot(); -}); - -function getWrapper(props = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginLicense-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginLicense-test.tsx deleted file mode 100644 index ecda6616b48..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginLicense-test.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 PluginLicense from '../PluginLicense'; - -it('should display the license field', () => { - expect(shallow()).toMatchSnapshot(); -}); - -it('should not display anything', () => { - expect(shallow().type()).toBeNull(); -}); diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginOrganization-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginOrganization-test.tsx deleted file mode 100644 index a9d3457e6ad..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginOrganization-test.tsx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 PluginOrganization, { PluginOrganizationProps } from '../PluginOrganization'; - -it('should render correctly', () => { - const wrapper = shallowRender(); - expect(wrapper).toMatchSnapshot(); -}); - -it('should render correctly with no organization name', () => { - const wrapper = shallowRender({ - plugin: { key: 'test', name: 'test', organizationName: undefined }, - }); - expect(wrapper.type()).toBeNull(); -}); - -function shallowRender(props?: Partial) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginRiskConsentBox-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginRiskConsentBox-test.tsx deleted file mode 100644 index 04eca18d869..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginRiskConsentBox-test.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { EditionKey } from '../../../../types/editions'; -import { RiskConsent } from '../../../../types/plugins'; -import PluginRiskConsentBox, { PluginRiskConsentBoxProps } from '../PluginRiskConsentBox'; - -it.each([[undefined], [RiskConsent.Accepted], [RiskConsent.NotAccepted], [RiskConsent.Required]])( - 'should render correctly for risk consent %s', - (riskConsent?: RiskConsent) => { - expect(shallowRender({ riskConsent })).toMatchSnapshot(); - } -); - -it('should render correctly for community edition', () => { - expect(shallowRender({ currentEdition: EditionKey.community })).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginUrls-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginUrls-test.tsx deleted file mode 100644 index 4bef5df74a8..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginUrls-test.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 PluginUrls from '../PluginUrls'; - -it('should display the urls', () => { - expect(getWrapper()).toMatchSnapshot(); -}); - -it('should display only one url', () => { - expect(getWrapper({ issueTrackerUrl: undefined })).toMatchSnapshot(); -}); - -it('should not display anything', () => { - expect(getWrapper({ homepageUrl: undefined, issueTrackerUrl: undefined }).type()).toBeNull(); -}); - -function getWrapper(plugin = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap deleted file mode 100644 index f239229c3d1..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap +++ /dev/null @@ -1,83 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display the edition 1`] = ` -
    -
    -
    -
    -

    - SonarQube logo - Developer Edition -

    -

    - - Built for Developers by Developers - -

    -

    - Community Edition functionality plus: -

    -
      -
    • - PR / MR decoration & Quality Gate - GitHub - GitLab - Azure DevOps - Bitbucket -
    • -
    • - Taint analysis / Injection flaw detection for Java, C#, PHP, Python, JS & TS -
    • -
    • - Branch analysis -
    • -
    • - Project aggregation -
    • -
    • - Additional languages: C, C++, Obj-C, PS/SQL, ABAP, TSQL & Swift -
    • -
    -
    -
    -
    -
    - - marketplace.request_free_trial - -
    -
    -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginActions-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginActions-test.tsx.snap deleted file mode 100644 index f0cbba99385..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginActions-test.tsx.snap +++ /dev/null @@ -1,116 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render available plugin correctly 1`] = ` -
    -

    - - - - - marketplace.terms_and_conditions - -

    - - - -
    -`; - -exports[`should render available plugin correctly 2`] = ` -
    -
    -

    - marketplace.available_under_commercial_license -

    -
    -
    -`; - -exports[`should render installed plugin correctly 1`] = ` -
    - - - - -
    -`; - -exports[`should render installed plugin correctly 2`] = ` -
    -

    - - marketplace.installed -

    -
    - -
    -
    -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginAvailable-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginAvailable-test.tsx.snap deleted file mode 100644 index 51aa9ac7916..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginAvailable-test.tsx.snap +++ /dev/null @@ -1,550 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = ` - - - -
      -
    • -
      - - 8.2 - -
      -
      - -
      -
    • -
    - - -
      - - - -
    - - - -`; - -exports[`should render correctly: has requirements 1`] = ` - - - -
      -
    • -
      - - 8.2 - -
      -
      - -

      - - marketplace.installing_this_plugin_will_also_install_x.Sonar Foo - -

      -
      -
    • -
    - - -
      - - - -
    - - - -`; - -exports[`should render correctly: has requirements, some of them already met 1`] = ` - - - -
      -
    • -
      - - 8.2 - -
      -
      - -

      - - marketplace.installing_this_plugin_will_also_install_x.Sonar Foo - -

      -
      -
    • -
    - - -
      - - - -
    - - - -`; - -exports[`should render correctly: read only 1`] = ` - - - -
      -
    • -
      - - 8.2 - -
      -
      - -
      -
    • -
    - - -
      - - - -
    - - -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginChangeLog-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginChangeLog-test.tsx.snap deleted file mode 100644 index bedb1f82654..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginChangeLog-test.tsx.snap +++ /dev/null @@ -1,105 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` -
    -
    - changelog -
    -
      - - - -
    -
    -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginDescription-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginDescription-test.tsx.snap deleted file mode 100644 index 3f3bf5627e5..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginDescription-test.tsx.snap +++ /dev/null @@ -1,44 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display the description and category 1`] = ` - -
    - - Foo - - - foocategory - -
    -
    - foo description -
    - -`; - -exports[`should not display any category 1`] = ` - -
    - - Foo - -
    -
    - foo description -
    - -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginLicense-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginLicense-test.tsx.snap deleted file mode 100644 index 648fe7b2ede..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginLicense-test.tsx.snap +++ /dev/null @@ -1,25 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display the license field 1`] = ` - -
  • - - SonarSource license - , - } - } - /> -
  • -
    -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginOrganization-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginOrganization-test.tsx.snap deleted file mode 100644 index 055f3c081ac..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginOrganization-test.tsx.snap +++ /dev/null @@ -1,24 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` -
  • - - org - , - } - } - /> -
  • -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginRiskConsentBox-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginRiskConsentBox-test.tsx.snap deleted file mode 100644 index 39b0f9ea863..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginRiskConsentBox-test.tsx.snap +++ /dev/null @@ -1,100 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly for community edition 1`] = ` -
    -

    - marketplace.risk_consent.title -

    -
    -

    - marketplace.risk_consent.description -

    -

    - marketplace.risk_consent.installation -

    - -
    -
    -`; - -exports[`should render correctly for risk consent ACCEPTED 1`] = `""`; - -exports[`should render correctly for risk consent NOT_ACCEPTED 1`] = ` -
    -

    - marketplace.risk_consent.title -

    -
    -

    - marketplace.risk_consent.description -

    - -
    -
    -`; - -exports[`should render correctly for risk consent REQUIRED 1`] = ` -
    -

    - marketplace.risk_consent.title -

    -
    -

    - marketplace.risk_consent.description -

    - -
    -
    -`; - -exports[`should render correctly for risk consent undefined 1`] = ` -
    -

    - marketplace.risk_consent.title -

    -
    -

    - marketplace.risk_consent.description -

    - -
    -
    -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginUrls-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginUrls-test.tsx.snap deleted file mode 100644 index 4a29b84eb51..00000000000 --- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginUrls-test.tsx.snap +++ /dev/null @@ -1,53 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display only one url 1`] = ` -
  • - -
  • -`; - -exports[`should display the urls 1`] = ` -
  • - -
  • -`; diff --git a/server/sonar-web/src/main/js/apps/marketplace/utils.ts b/server/sonar-web/src/main/js/apps/marketplace/utils.ts index fbd5ab8fc56..8b93d2ecedb 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/utils.ts +++ b/server/sonar-web/src/main/js/apps/marketplace/utils.ts @@ -17,9 +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 { memoize } from 'lodash'; +import { findLastIndex, memoize } from 'lodash'; +import { getInstalledPlugins, getUpdatesPlugins } from '../../api/plugins'; +import { throwGlobalError } from '../../helpers/error'; import { cleanQuery, parseAsString, serializeString } from '../../helpers/query'; -import { Plugin } from '../../types/plugins'; +import { isDefined } from '../../helpers/types'; +import { InstalledPlugin, Plugin, Update } from '../../types/plugins'; import { RawQuery } from '../../types/types'; export interface Query { @@ -59,3 +62,68 @@ export const serializeQuery = memoize( search: query.search ? serializeString(query.search) : undefined, }) ); + +function getLastUpdates(updates: undefined | Update[]): Update[] { + if (!updates) { + return []; + } + const lastUpdate = ['COMPATIBLE', 'REQUIRES_SYSTEM_UPGRADE', 'DEPS_REQUIRE_SYSTEM_UPGRADE'].map( + (status) => { + const index = findLastIndex(updates, (update) => update.status === status); + return index > -1 ? updates[index] : undefined; + } + ); + return lastUpdate.filter(isDefined); +} + +function addChangelog(update: Update, updates?: Update[]) { + if (!updates) { + return update; + } + const index = updates.indexOf(update); + const previousUpdates = index > 0 ? updates.slice(0, index) : []; + return { ...update, previousUpdates }; +} + +export function getInstalledPluginsWithUpdates(): Promise { + return Promise.all([getInstalledPlugins(), getUpdatesPlugins()]) + .then(([installed, updates]) => + installed.map((plugin: InstalledPlugin) => { + const updatePlugin: InstalledPlugin = updates.plugins.find( + (p: InstalledPlugin) => p.key === plugin.key + ); + if (updatePlugin) { + return { + ...updatePlugin, + ...plugin, + updates: getLastUpdates(updatePlugin.updates).map((update) => + addChangelog(update, updatePlugin.updates) + ), + }; + } + return plugin; + }) + ) + .catch(throwGlobalError); +} + +export function getPluginUpdates(): Promise { + return Promise.all([getUpdatesPlugins(), getInstalledPlugins()]) + .then(([updates, installed]) => + updates.plugins.map((updatePlugin: InstalledPlugin) => { + const updates = getLastUpdates(updatePlugin.updates).map((update) => + addChangelog(update, updatePlugin.updates) + ); + const plugin = installed.find((p: InstalledPlugin) => p.key === updatePlugin.key); + if (plugin) { + return { + ...plugin, + ...updatePlugin, + updates, + }; + } + return { ...updatePlugin, updates }; + }) + ) + .catch(throwGlobalError); +} diff --git a/server/sonar-web/src/main/js/helpers/testSelector.ts b/server/sonar-web/src/main/js/helpers/testSelector.ts index e558c9ce014..832aca63258 100644 --- a/server/sonar-web/src/main/js/helpers/testSelector.ts +++ b/server/sonar-web/src/main/js/helpers/testSelector.ts @@ -112,14 +112,14 @@ class ChainDispatch extends ChainingQuery { container?: HTMLElement, waitForOptions?: waitForOptions ) { - return this.elementQuery.get(await this.insideQuery.find(container, waitForOptions)); + return this.elementQuery.find(await this.insideQuery.find(container, waitForOptions)); } async findAll( container?: HTMLElement, waitForOptions?: waitForOptions ) { - return this.elementQuery.getAll(await this.insideQuery.find(container, waitForOptions)); + return this.elementQuery.findAll(await this.insideQuery.find(container, waitForOptions)); } get(container?: HTMLElement) { @@ -131,11 +131,19 @@ class ChainDispatch extends ChainingQuery { } query(container?: HTMLElement) { - return this.elementQuery.query(this.insideQuery.get(container)); + const innerContainer = this.insideQuery.query(container); + if (innerContainer) { + return this.elementQuery.query(innerContainer); + } + return null; } queryAll(container?: HTMLElement) { - return this.elementQuery.queryAll(this.insideQuery.get(container)); + const innerContainer = this.insideQuery.query(container); + if (innerContainer) { + return this.elementQuery.queryAll(innerContainer); + } + return null; } } -- 2.39.5