aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2019-03-29 18:39:32 +0100
committerSonarTech <sonartech@sonarsource.com>2019-04-04 20:21:04 +0200
commit2af145e34db52a865a16d36c85fb8d83a9cf1351 (patch)
tree0a907676728ff0d60b1c1275426929432bb8c118 /server/sonar-web/src/main/js
parentbddb35d5e638c63146846fbea96141d2f908c2b2 (diff)
downloadsonarqube-2af145e34db52a865a16d36c85fb8d83a9cf1351.tar.gz
sonarqube-2af145e34db52a865a16d36c85fb8d83a9cf1351.zip
Add some more coverage
Diffstat (limited to 'server/sonar-web/src/main/js')
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx11
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMeta-test.tsx68
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap20
-rw-r--r--server/sonar-web/src/main/js/apps/account/profile/Profile.tsx34
-rw-r--r--server/sonar-web/src/main/js/apps/account/profile/__tests__/Profile-test.tsx59
-rw-r--r--server/sonar-web/src/main/js/apps/account/profile/__tests__/__snapshots__/Profile-test.tsx.snap58
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginActions-test.tsx58
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginActions-test.tsx.snap116
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaContainer-test.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaContainer-test.tsx.snap96
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileProjects-test.tsx56
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileProjects-test.tsx.snap95
-rw-r--r--server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItemIdentity-test.tsx86
-rw-r--r--server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UserListItemIdentity-test.tsx.snap80
15 files changed, 790 insertions, 50 deletions
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx
index 08ca22507ba..9694df8232b 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx
@@ -36,12 +36,9 @@ import { translate } from '../../../../helpers/l10n';
import { isLoggedIn } from '../../../../helpers/users';
import { getCurrentUser, Store } from '../../../../store/rootReducer';
-interface StateProps {
- currentUser: T.CurrentUser;
-}
-
-interface Props extends StateProps {
+export interface Props {
branchLike?: T.BranchLike;
+ currentUser: T.CurrentUser;
component: T.Component;
warnings: string[];
}
@@ -100,7 +97,7 @@ export function ComponentNavMeta({ branchLike, component, currentUser, warnings
);
}
-function getCurrentPage(component: T.Component, branchLike: T.BranchLike | undefined) {
+export function getCurrentPage(component: T.Component, branchLike: T.BranchLike | undefined) {
let currentPage: T.HomePage | undefined;
if (component.qualifier === 'VW' || component.qualifier === 'SVW') {
currentPage = { type: 'PORTFOLIO', component: component.key };
@@ -115,7 +112,7 @@ function getCurrentPage(component: T.Component, branchLike: T.BranchLike | undef
return currentPage;
}
-const mapStateToProps = (state: Store): StateProps => ({
+const mapStateToProps = (state: Store) => ({
currentUser: getCurrentUser(state)
});
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMeta-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMeta-test.tsx
index 8888565e814..acc42d006cf 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMeta-test.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMeta-test.tsx
@@ -19,40 +19,70 @@
*/
import * as React from 'react';
import { shallow } from 'enzyme';
-import { ComponentNavMeta } from '../ComponentNavMeta';
+import { ComponentNavMeta, getCurrentPage, Props } from '../ComponentNavMeta';
import {
mockShortLivingBranch,
mockComponent,
mockLongLivingBranch,
- mockPullRequest
+ mockPullRequest,
+ mockCurrentUser,
+ mockLoggedInUser
} from '../../../../../helpers/testMocks';
-it('renders status of short-living branch', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
+describe('#ComponentNavMeta', () => {
+ it('renders status of short-living branch', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ });
-it('renders meta for long-living branch', () => {
- expect(shallowRender({ branchLike: mockLongLivingBranch() })).toMatchSnapshot();
-});
+ it('renders meta for long-living branch', () => {
+ expect(
+ shallowRender({ branchLike: mockLongLivingBranch(), currentUser: mockLoggedInUser() })
+ ).toMatchSnapshot();
+ });
-it('renders meta for pull request', () => {
- expect(
- shallowRender({
- branchLike: mockPullRequest({
- url: 'https://example.com/pull/1234'
+ it('renders meta for pull request', () => {
+ expect(
+ shallowRender({
+ branchLike: mockPullRequest({
+ url: 'https://example.com/pull/1234'
+ })
})
- })
- ).toMatchSnapshot();
+ ).toMatchSnapshot();
+ });
+});
+
+describe('#getCurrentPage', () => {
+ it('should return a portfolio page', () => {
+ expect(getCurrentPage(mockComponent({ key: 'foo', qualifier: 'VW' }), undefined)).toEqual({
+ type: 'PORTFOLIO',
+ component: 'foo'
+ });
+ });
+
+ it('should return an app page', () => {
+ expect(
+ getCurrentPage(
+ mockComponent({ key: 'foo', qualifier: 'APP' }),
+ mockLongLivingBranch({ name: 'develop' })
+ )
+ ).toEqual({ type: 'APPLICATION', component: 'foo', branch: 'develop' });
+ });
+
+ it('should return a portfolio page', () => {
+ expect(getCurrentPage(mockComponent(), mockShortLivingBranch())).toEqual({
+ type: 'PROJECT',
+ component: 'my-project',
+ branch: undefined
+ });
+ });
});
-function shallowRender(props = {}) {
+function shallowRender(props: Partial<Props> = {}) {
return shallow(
<ComponentNavMeta
branchLike={mockShortLivingBranch()}
component={mockComponent({ analysisDate: '2017-01-02T00:00:00.000Z', version: '0.0.1' })}
- currentUser={{
- isLoggedIn: false
- }}
+ currentUser={mockCurrentUser()}
warnings={[]}
{...props}
/>
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap
index fdd4a833114..e8ea68e5742 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`renders meta for long-living branch 1`] = `
+exports[`#ComponentNavMeta renders meta for long-living branch 1`] = `
<div
className="navbar-context-meta"
>
@@ -23,10 +23,24 @@ exports[`renders meta for long-living branch 1`] = `
0.0.1
</div>
</Tooltip>
+ <div
+ className="navbar-context-meta-secondary"
+ >
+ <Connect(HomePageSelect)
+ className="spacer-left"
+ currentPage={
+ Object {
+ "branch": "master",
+ "component": "my-project",
+ "type": "PROJECT",
+ }
+ }
+ />
+ </div>
</div>
`;
-exports[`renders meta for pull request 1`] = `
+exports[`#ComponentNavMeta renders meta for pull request 1`] = `
<div
className="navbar-context-meta"
>
@@ -69,7 +83,7 @@ exports[`renders meta for pull request 1`] = `
</div>
`;
-exports[`renders status of short-living branch 1`] = `
+exports[`#ComponentNavMeta renders status of short-living branch 1`] = `
<div
className="navbar-context-meta"
>
diff --git a/server/sonar-web/src/main/js/apps/account/profile/Profile.tsx b/server/sonar-web/src/main/js/apps/account/profile/Profile.tsx
index 000c9dd86cb..73c6f255596 100644
--- a/server/sonar-web/src/main/js/apps/account/profile/Profile.tsx
+++ b/server/sonar-web/src/main/js/apps/account/profile/Profile.tsx
@@ -18,56 +18,50 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { connect } from 'react-redux';
import UserExternalIdentity from './UserExternalIdentity';
import UserGroups from './UserGroups';
import UserScmAccounts from './UserScmAccounts';
-import { getCurrentUser, areThereCustomOrganizations, Store } from '../../../store/rootReducer';
import { translate } from '../../../helpers/l10n';
+import { isSonarCloud } from '../../../helpers/system';
+import { whenLoggedIn } from '../../../components/hoc/whenLoggedIn';
-interface Props {
- customOrganizations?: boolean;
- user: T.LoggedInUser;
+export interface Props {
+ currentUser: T.LoggedInUser;
}
-function Profile({ customOrganizations, user }: Props) {
+export function Profile({ currentUser }: Props) {
return (
<div className="account-body account-container">
<div className="boxed-group boxed-group-inner">
<div className="spacer-bottom">
- {translate('login')}: <strong id="login">{user.login}</strong>
+ {translate('login')}: <strong id="login">{currentUser.login}</strong>
</div>
- {!user.local && user.externalProvider !== 'sonarqube' && (
+ {!currentUser.local && currentUser.externalProvider !== 'sonarqube' && (
<div className="spacer-bottom" id="identity-provider">
- <UserExternalIdentity user={user} />
+ <UserExternalIdentity user={currentUser} />
</div>
)}
- {!!user.email && (
+ {Boolean(currentUser.email) && (
<div className="spacer-bottom">
- {translate('my_profile.email')}: <strong id="email">{user.email}</strong>
+ {translate('my_profile.email')}: <strong id="email">{currentUser.email}</strong>
</div>
)}
- {!customOrganizations && (
+ {!isSonarCloud() && (
<>
<hr className="account-separator" />
- <UserGroups groups={user.groups} />
+ <UserGroups groups={currentUser.groups} />
</>
)}
<hr />
- <UserScmAccounts scmAccounts={user.scmAccounts} user={user} />
+ <UserScmAccounts scmAccounts={currentUser.scmAccounts} user={currentUser} />
</div>
</div>
);
}
-const mapStateToProps = (state: Store) => ({
- customOrganizations: areThereCustomOrganizations(state),
- user: getCurrentUser(state) as T.LoggedInUser
-});
-
-export default connect(mapStateToProps)(Profile);
+export default whenLoggedIn(Profile);
diff --git a/server/sonar-web/src/main/js/apps/account/profile/__tests__/Profile-test.tsx b/server/sonar-web/src/main/js/apps/account/profile/__tests__/Profile-test.tsx
new file mode 100644
index 00000000000..4ef71994b28
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/account/profile/__tests__/Profile-test.tsx
@@ -0,0 +1,59 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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 * as React from 'react';
+import { shallow } from 'enzyme';
+import { Profile, Props } from '../Profile';
+import { mockLoggedInUser } from '../../../../helpers/testMocks';
+import { isSonarCloud } from '../../../../helpers/system';
+
+jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn().mockReturnValue(false) }));
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+});
+
+it('should render email', () => {
+ expect(
+ shallowRender(mockLoggedInUser({ email: 'john@doe.com' }))
+ .find('#email')
+ .exists()
+ ).toBe(true);
+});
+
+it('should render external identity', () => {
+ expect(
+ shallowRender(mockLoggedInUser({ local: false, externalProvider: 'github' }))
+ .find('UserExternalIdentity')
+ .exists()
+ ).toBe(true);
+});
+
+it('should not display user groups', () => {
+ (isSonarCloud as jest.Mock).mockReturnValueOnce(true);
+ expect(
+ shallowRender()
+ .find('UserGroups')
+ .exists()
+ ).toBe(false);
+});
+
+function shallowRender(currentUser: Props['currentUser'] = mockLoggedInUser()) {
+ return shallow(<Profile currentUser={currentUser} />);
+}
diff --git a/server/sonar-web/src/main/js/apps/account/profile/__tests__/__snapshots__/Profile-test.tsx.snap b/server/sonar-web/src/main/js/apps/account/profile/__tests__/__snapshots__/Profile-test.tsx.snap
new file mode 100644
index 00000000000..e896064c035
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/account/profile/__tests__/__snapshots__/Profile-test.tsx.snap
@@ -0,0 +1,58 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="account-body account-container"
+>
+ <div
+ className="boxed-group boxed-group-inner"
+ >
+ <div
+ className="spacer-bottom"
+ >
+ login
+ :
+ <strong
+ id="login"
+ >
+ luke
+ </strong>
+ </div>
+ <div
+ className="spacer-bottom"
+ id="identity-provider"
+ >
+ <UserExternalIdentity
+ user={
+ Object {
+ "groups": Array [],
+ "isLoggedIn": true,
+ "login": "luke",
+ "name": "Skywalker",
+ "scmAccounts": Array [],
+ }
+ }
+ />
+ </div>
+ <hr
+ className="account-separator"
+ />
+ <UserGroups
+ groups={Array []}
+ />
+ <hr />
+ <UserScmAccounts
+ scmAccounts={Array []}
+ user={
+ Object {
+ "groups": Array [],
+ "isLoggedIn": true,
+ "login": "luke",
+ "name": "Skywalker",
+ "scmAccounts": Array [],
+ }
+ }
+ />
+ </div>
+</div>
+`;
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
new file mode 100644
index 00000000000..646d5b849ae
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/PluginActions-test.tsx
@@ -0,0 +1,58 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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 * as React from 'react';
+import { shallow } from 'enzyme';
+import PluginActions from '../PluginActions';
+import { PluginInstalled, PluginAvailable } from '../../../../api/plugins';
+
+const installedPlugin: PluginInstalled = {
+ 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: PluginAvailable = {
+ 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<PluginActions['props']> = {}) {
+ return shallow(<PluginActions plugin={installedPlugin} refreshPending={jest.fn()} {...props} />);
+}
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
new file mode 100644
index 00000000000..dc924345af0
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginActions-test.tsx.snap
@@ -0,0 +1,116 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render available plugin correctly 1`] = `
+<div
+ className="js-actions"
+>
+ <p
+ className="little-spacer-bottom"
+ >
+ <Checkbox
+ checked={false}
+ className="js-terms"
+ id="plugin-terms-foo"
+ onCheck={[Function]}
+ thirdState={false}
+ >
+ <label
+ className="little-spacer-left"
+ htmlFor="plugin-terms-foo"
+ >
+ marketplace.i_accept_the
+ </label>
+ </Checkbox>
+ <a
+ className="js-plugin-terms nowrap little-spacer-left"
+ href="https://url"
+ target="_blank"
+ >
+ marketplace.terms_and_conditions
+ </a>
+ </p>
+ <Button
+ className="js-install"
+ disabled={true}
+ onClick={[Function]}
+ >
+ marketplace.install
+ </Button>
+</div>
+`;
+
+exports[`should render available plugin correctly 2`] = `
+<div
+ className="js-actions"
+>
+ <div>
+ <p
+ className="little-spacer-bottom"
+ >
+ marketplace.available_under_commercial_license
+ </p>
+ <a
+ target="_blank"
+ >
+ marketplace.learn_more
+ </a>
+ </div>
+</div>
+`;
+
+exports[`should render installed plugin correctly 1`] = `
+<div
+ className="js-actions"
+>
+ <div
+ className="display-inlin-block"
+ >
+ <PluginUpdateButton
+ disabled={false}
+ key="0"
+ onClick={[Function]}
+ update={
+ Object {
+ "requires": Array [],
+ "status": "COMPATIBLE",
+ }
+ }
+ />
+ <Button
+ className="js-uninstall button-red little-spacer-left"
+ disabled={false}
+ onClick={[Function]}
+ >
+ marketplace.uninstall
+ </Button>
+ </div>
+</div>
+`;
+
+exports[`should render installed plugin correctly 2`] = `
+<div
+ className="js-actions"
+>
+ <p>
+ <CheckIcon
+ className="little-spacer-right"
+ />
+ marketplace.installed
+ </p>
+ <div
+ className="spacer-top"
+ >
+ <PluginUpdateButton
+ disabled={false}
+ key="0"
+ onClick={[Function]}
+ update={
+ Object {
+ "requires": Array [],
+ "status": "COMPATIBLE",
+ }
+ }
+ />
+ </div>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaContainer-test.tsx b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaContainer-test.tsx
index 99b5e123b8d..be344becf16 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaContainer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaContainer-test.tsx
@@ -59,6 +59,7 @@ function shallowRender(props: Partial<Meta['props']> = {}) {
appState={mockAppState({ organizationsEnabled: true })}
component={mockComponent()}
currentUser={mockLoggedInUser()}
+ metrics={{}}
onComponentChange={jest.fn()}
organization={mockOrganization()}
userOrganizations={[mockOrganization()]}
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaContainer-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaContainer-test.tsx.snap
index fc95c357f57..d6c60fc0d8b 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaContainer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaContainer-test.tsx.snap
@@ -39,6 +39,33 @@ exports[`should hide QG and QP links if the organization has a paid plan, and th
onComponentChange={[MockFunction]}
/>
</div>
+ <AnalysesList
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ metrics={Object {}}
+ qualifier="TRK"
+ />
<MetaLinks
component={
Object {
@@ -75,6 +102,11 @@ exports[`should hide QG and QP links if the organization has a paid plan, and th
organization="foo"
/>
</div>
+ <BadgesModal
+ metrics={Object {}}
+ project="my-project"
+ qualifier="TRK"
+ />
</div>
`;
@@ -117,6 +149,33 @@ exports[`should render correctly 1`] = `
onComponentChange={[MockFunction]}
/>
</div>
+ <AnalysesList
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ metrics={Object {}}
+ qualifier="TRK"
+ />
<div
className="overview-meta-card"
id="overview-meta-quality-gate"
@@ -182,6 +241,11 @@ exports[`should render correctly 1`] = `
organization="foo"
/>
</div>
+ <BadgesModal
+ metrics={Object {}}
+ project="my-project"
+ qualifier="TRK"
+ />
</div>
`;
@@ -224,6 +288,33 @@ exports[`should show QG and QP links if the organization has a paid plan, and th
onComponentChange={[MockFunction]}
/>
</div>
+ <AnalysesList
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ metrics={Object {}}
+ qualifier="TRK"
+ />
<div
className="overview-meta-card"
id="overview-meta-quality-gate"
@@ -289,5 +380,10 @@ exports[`should show QG and QP links if the organization has a paid plan, and th
organization="foo"
/>
</div>
+ <BadgesModal
+ metrics={Object {}}
+ project="my-project"
+ qualifier="TRK"
+ />
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileProjects-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileProjects-test.tsx
new file mode 100644
index 00000000000..dcfdaabdb0e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileProjects-test.tsx
@@ -0,0 +1,56 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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 * as React from 'react';
+import { shallow } from 'enzyme';
+import ProfileProjects from '../ProfileProjects';
+import { mockQualityProfile } from '../../../../helpers/testMocks';
+import { waitAndUpdate } from '../../../../helpers/testUtils';
+
+jest.mock('../../../../api/quality-profiles', () => ({
+ getProfileProjects: jest.fn().mockResolvedValue({
+ results: [
+ {
+ id: '633a5180-1ad7-4008-a5cb-e1d3cec4c816',
+ key: 'org.sonarsource.xml:xml',
+ name: 'SonarXML',
+ selected: true
+ }
+ ],
+ paging: { pageIndex: 1, pageSize: 2, total: 10 },
+ more: true
+ })
+}));
+
+it('should render correctly', async () => {
+ const wrapper = shallowRender();
+ expect(wrapper).toMatchSnapshot();
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<ProfileProjects['props']> = {}) {
+ return shallow(
+ <ProfileProjects
+ organization="foo"
+ profile={mockQualityProfile({ actions: { associateProjects: true } })}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileProjects-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileProjects-test.tsx.snap
new file mode 100644
index 00000000000..de37df033c2
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileProjects-test.tsx.snap
@@ -0,0 +1,95 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="boxed-group quality-profile-projects"
+>
+ <div
+ className="boxed-group-actions"
+ >
+ <Button
+ className="js-change-projects"
+ onClick={[Function]}
+ >
+ quality_profiles.change_projects
+ </Button>
+ </div>
+ <header
+ className="boxed-group-header"
+ >
+ <h2>
+ projects
+ </h2>
+ </header>
+ <div
+ className="boxed-group-inner"
+ >
+ <i
+ className="spinner"
+ />
+ </div>
+</div>
+`;
+
+exports[`should render correctly 2`] = `
+<div
+ className="boxed-group quality-profile-projects"
+>
+ <div
+ className="boxed-group-actions"
+ >
+ <Button
+ className="js-change-projects"
+ onClick={[Function]}
+ >
+ quality_profiles.change_projects
+ </Button>
+ </div>
+ <header
+ className="boxed-group-header"
+ >
+ <h2>
+ projects
+ </h2>
+ </header>
+ <div
+ className="boxed-group-inner"
+ >
+ <ul>
+ <li
+ className="spacer-top js-profile-project"
+ data-key="org.sonarsource.xml:xml"
+ key="org.sonarsource.xml:xml"
+ >
+ <Link
+ className="link-with-icon"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "query": Object {
+ "id": "org.sonarsource.xml:xml",
+ },
+ }
+ }
+ >
+ <QualifierIcon
+ qualifier="TRK"
+ />
+
+ <span>
+ SonarXML
+ </span>
+ </Link>
+ </li>
+ </ul>
+ <ListFooter
+ count={1}
+ loadMore={[Function]}
+ ready={true}
+ total={10}
+ />
+ </div>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx b/server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx
index 9d6c85ebecf..b4e53b19b55 100644
--- a/server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx
+++ b/server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx
@@ -22,7 +22,7 @@ import * as theme from '../../../app/theme';
import { getTextColor } from '../../../helpers/colors';
import { getBaseUrl } from '../../../helpers/urls';
-interface Props {
+export interface Props {
identityProvider?: T.IdentityProvider;
user: T.User;
}
diff --git a/server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItemIdentity-test.tsx b/server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItemIdentity-test.tsx
new file mode 100644
index 00000000000..126e2aebac5
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItemIdentity-test.tsx
@@ -0,0 +1,86 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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 * as React from 'react';
+import { shallow } from 'enzyme';
+import UserListItemIdentity, { Props, ExternalProvider } from '../UserListItemIdentity';
+
+describe('#UserListItemIdentity', () => {
+ it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ });
+
+ function shallowRender(props: Partial<Props> = {}) {
+ return shallow(
+ <UserListItemIdentity
+ identityProvider={{
+ backgroundColor: 'blue',
+ iconPath: 'icon/path',
+ key: 'foo',
+ name: 'Foo Provider'
+ }}
+ user={{
+ active: true,
+ email: 'obi.one@empire',
+ externalProvider: 'foo',
+ lastConnectionDate: '2019-01-18T15:06:33+0100',
+ local: false,
+ login: 'obi',
+ name: 'One',
+ scmAccounts: []
+ }}
+ {...props}
+ />
+ );
+ }
+});
+
+describe('#ExternalProvider', () => {
+ it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ });
+
+ it('should render the user external provider and identity', () => {
+ expect(shallowRender({ identityProvider: undefined })).toMatchSnapshot();
+ });
+
+ function shallowRender(props: Partial<Props> = {}) {
+ return shallow(
+ <ExternalProvider
+ identityProvider={{
+ backgroundColor: 'blue',
+ iconPath: 'icon/path',
+ key: 'foo',
+ name: 'Foo Provider'
+ }}
+ user={{
+ active: true,
+ email: 'obi.one@empire',
+ externalProvider: 'foo',
+ lastConnectionDate: '2019-01-18T15:06:33+0100',
+ local: false,
+ login: 'obi',
+ name: 'One',
+ scmAccounts: []
+ }}
+ {...props}
+ />
+ );
+ }
+});
diff --git a/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UserListItemIdentity-test.tsx.snap b/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UserListItemIdentity-test.tsx.snap
new file mode 100644
index 00000000000..c9d65154d56
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UserListItemIdentity-test.tsx.snap
@@ -0,0 +1,80 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`#ExternalProvider should render correctly 1`] = `
+<div
+ className="js-user-identity-provider little-spacer-top"
+>
+ <div
+ className="identity-provider"
+ style={
+ Object {
+ "backgroundColor": "blue",
+ "color": "#fff",
+ }
+ }
+ >
+ <img
+ alt="Foo Provider"
+ className="little-spacer-right"
+ height="14"
+ src="icon/path"
+ width="14"
+ />
+ </div>
+</div>
+`;
+
+exports[`#ExternalProvider should render the user external provider and identity 1`] = `
+<div
+ className="js-user-identity-provider little-spacer-top"
+>
+ <span>
+ foo
+ :
+ </span>
+</div>
+`;
+
+exports[`#UserListItemIdentity should render correctly 1`] = `
+<td>
+ <div>
+ <strong
+ className="js-user-name"
+ >
+ One
+ </strong>
+ <span
+ className="js-user-login note little-spacer-left"
+ >
+ obi
+ </span>
+ </div>
+ <div
+ className="js-user-email little-spacer-top"
+ >
+ obi.one@empire
+ </div>
+ <ExternalProvider
+ identityProvider={
+ Object {
+ "backgroundColor": "blue",
+ "iconPath": "icon/path",
+ "key": "foo",
+ "name": "Foo Provider",
+ }
+ }
+ user={
+ Object {
+ "active": true,
+ "email": "obi.one@empire",
+ "externalProvider": "foo",
+ "lastConnectionDate": "2019-01-18T15:06:33+0100",
+ "local": false,
+ "login": "obi",
+ "name": "One",
+ "scmAccounts": Array [],
+ }
+ }
+ />
+</td>
+`;