aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorWouter Admiraal <wouter.admiraal@sonarsource.com>2019-03-07 13:30:28 +0100
committersonartech <sonartech@sonarsource.com>2019-03-26 13:37:56 +0100
commit62a8287557d8ea46c6d09a9acd679f1e3c5f01cd (patch)
tree88bdcde6d3d7379f6c82d3e757b9d6465e50cef3 /server/sonar-web
parent16f267a80f2863f4ff4c2d609584d4cc0fbaae76 (diff)
downloadsonarqube-62a8287557d8ea46c6d09a9acd679f1e3c5f01cd.tar.gz
sonarqube-62a8287557d8ea46c6d09a9acd679f1e3c5f01cd.zip
Add tests for untested components
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/app/components/GlobalContainer.tsx2
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/GlobalContainer-test.tsx51
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/ProjectAdminContainer-test.tsx71
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap41
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/ProjectAdminContainer-test.tsx.snap40
-rw-r--r--server/sonar-web/src/main/js/app/components/a11y/__tests__/A11yProvider-test.tsx7
-rw-r--r--server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/about/components/__tests__/AboutApp-test.tsx87
-rw-r--r--server/sonar-web/src/main/js/apps/about/components/__tests__/__snapshots__/AboutApp-test.tsx.snap1253
-rw-r--r--server/sonar-web/src/main/js/apps/account/components/Account.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/account/components/__tests__/Account-test.tsx43
-rw-r--r--server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Account-test.tsx.snap36
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap12
-rw-r--r--server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx51
-rw-r--r--server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap71
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx89
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap118
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap4
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/App-test.tsx.snap10
-rw-r--r--server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/web-api/components/__tests__/WebApiApp-test.tsx82
-rw-r--r--server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/WebApiApp-test.tsx.snap119
-rw-r--r--server/sonar-web/src/main/js/components/hoc/__tests__/whenLoggedIn-test.tsx15
-rw-r--r--server/sonar-web/src/main/js/components/hoc/__tests__/withCurrentUser-test.tsx7
-rw-r--r--server/sonar-web/src/main/js/components/hoc/__tests__/withUserOrganizations-test.tsx12
-rw-r--r--server/sonar-web/src/main/js/helpers/testMocks.ts21
30 files changed, 2220 insertions, 54 deletions
diff --git a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx
index 3e5e40382ee..51d7dc41985 100644
--- a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx
+++ b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx
@@ -27,7 +27,7 @@ import A11yProvider from './a11y/A11yProvider';
import A11ySkipLinks from './a11y/A11ySkipLinks';
import Workspace from '../../components/workspace/Workspace';
-interface Props {
+export interface Props {
children: React.ReactNode;
footer?: React.ReactNode;
location: { pathname: string };
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/GlobalContainer-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/GlobalContainer-test.tsx
new file mode 100644
index 00000000000..ff7aba0434b
--- /dev/null
+++ b/server/sonar-web/src/main/js/app/components/__tests__/GlobalContainer-test.tsx
@@ -0,0 +1,51 @@
+/*
+ * 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 GlobalContainer, { Props } from '../GlobalContainer';
+import { mockLocation } from '../../../helpers/testMocks';
+
+jest.mock('../embed-docs-modal/SuggestionsProvider', () => {
+ class SuggestionsProvider extends React.Component {
+ render() {
+ return this.props.children;
+ }
+ }
+
+ return { default: SuggestionsProvider };
+});
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<Props> = {}) {
+ class ChildComponent extends React.Component {
+ render() {
+ return null;
+ }
+ }
+
+ return shallow(
+ <GlobalContainer location={mockLocation()} {...props}>
+ <ChildComponent />
+ </GlobalContainer>
+ );
+}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/ProjectAdminContainer-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/ProjectAdminContainer-test.tsx
new file mode 100644
index 00000000000..2935e1b2686
--- /dev/null
+++ b/server/sonar-web/src/main/js/app/components/__tests__/ProjectAdminContainer-test.tsx
@@ -0,0 +1,71 @@
+/*
+ * 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 { mount, shallow } from 'enzyme';
+import ProjectAdminContainer from '../ProjectAdminContainer';
+import handleRequiredAuthorization from '../../utils/handleRequiredAuthorization';
+import { mockComponent } from '../../../helpers/testMocks';
+
+jest.mock('../../utils/handleRequiredAuthorization', () => {
+ return { default: jest.fn() };
+});
+
+class ChildComponent extends React.Component {
+ render() {
+ return null;
+ }
+}
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+});
+
+it('should redirect for authorization if needed', () => {
+ mountRender({ component: mockComponent({ configuration: { showSettings: false } }) });
+ expect(handleRequiredAuthorization).toBeCalled();
+});
+
+it('should pass props to its children', () => {
+ const child = shallowRender().find(ChildComponent);
+ // No need to check all...
+ expect(child.prop('component')).toBeDefined();
+ expect(child.prop('onBranchesChange')).toBeDefined();
+});
+
+function mountRender(props: Partial<ProjectAdminContainer['props']> = {}) {
+ return mount(createComponent(props));
+}
+
+function shallowRender(props: Partial<ProjectAdminContainer['props']> = {}) {
+ return shallow(createComponent(props));
+}
+
+function createComponent(props: Partial<ProjectAdminContainer['props']> = {}) {
+ return (
+ <ProjectAdminContainer
+ branchLikes={[]}
+ component={mockComponent({ configuration: { showSettings: true } })}
+ onBranchesChange={jest.fn()}
+ onComponentChange={jest.fn()}
+ {...props}>
+ <ChildComponent />
+ </ProjectAdminContainer>
+ );
+}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap
new file mode 100644
index 00000000000..484a153d105
--- /dev/null
+++ b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap
@@ -0,0 +1,41 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<SuggestionsProvider>
+ <A11yProvider>
+ <Connect(withRouter(StartupModal))>
+ <A11ySkipLinks />
+ <div
+ className="global-container"
+ >
+ <div
+ className="page-wrapper"
+ id="container"
+ >
+ <div
+ className="page-container"
+ >
+ <Workspace>
+ <Connect(GlobalNav)
+ location={
+ Object {
+ "action": "PUSH",
+ "key": "key",
+ "pathname": "/path",
+ "query": Object {},
+ "search": "",
+ "state": Object {},
+ }
+ }
+ />
+ <Connect(GlobalMessages) />
+ <ChildComponent />
+ </Workspace>
+ </div>
+ </div>
+ <Connect(GlobalFooter) />
+ </div>
+ </Connect(withRouter(StartupModal))>
+ </A11yProvider>
+</SuggestionsProvider>
+`;
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/ProjectAdminContainer-test.tsx.snap b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/ProjectAdminContainer-test.tsx.snap
new file mode 100644
index 00000000000..7277c60ef83
--- /dev/null
+++ b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/ProjectAdminContainer-test.tsx.snap
@@ -0,0 +1,40 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Fragment>
+ <A11ySkipTarget
+ anchor="admin_main"
+ />
+ <ChildComponent
+ branchLikes={Array []}
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "configuration": Object {
+ "showSettings": true,
+ },
+ "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 [],
+ }
+ }
+ onBranchesChange={[MockFunction]}
+ onComponentChange={[MockFunction]}
+ />
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/app/components/a11y/__tests__/A11yProvider-test.tsx b/server/sonar-web/src/main/js/app/components/a11y/__tests__/A11yProvider-test.tsx
index 98f64d3db6f..22b5e650320 100644
--- a/server/sonar-web/src/main/js/app/components/a11y/__tests__/A11yProvider-test.tsx
+++ b/server/sonar-web/src/main/js/app/components/a11y/__tests__/A11yProvider-test.tsx
@@ -23,16 +23,17 @@ import { A11yContextShape } from '../A11yContext';
import A11yProvider from '../A11yProvider';
import { waitAndUpdate } from '../../../../helpers/testUtils';
-const link1 = { key: 'link1', label: 'Link 1' };
+const link1 = { key: 'link1', label: 'Link 1', weight: 0 };
const link2 = { key: 'link2', label: 'Link 2', weight: -10 };
-const link3 = { key: 'link3', label: 'Link 3' };
+const link3 = { key: 'link3', label: 'Link 3', weight: 0 };
it('should allow to register new skip links', () => {
const wrapper = shallowRender();
const instance = wrapper.instance();
expect(wrapper.state('links')).toEqual([]);
- instance.addA11ySkipLink(link1);
+ // Check that an absence of weight is treated as "0".
+ instance.addA11ySkipLink({ ...link1, weight: undefined });
expect(wrapper.state('links')).toEqual([link1]);
instance.addA11ySkipLink(link2);
diff --git a/server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx b/server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx
index 061b7c1b3ad..4e93eb52bac 100644
--- a/server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx
+++ b/server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx
@@ -60,7 +60,7 @@ interface State {
projectsCount: number;
}
-class AboutApp extends React.PureComponent<Props, State> {
+export class AboutApp extends React.PureComponent<Props, State> {
mounted = false;
state: State = {
diff --git a/server/sonar-web/src/main/js/apps/about/components/__tests__/AboutApp-test.tsx b/server/sonar-web/src/main/js/apps/about/components/__tests__/AboutApp-test.tsx
new file mode 100644
index 00000000000..f18f087816e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/about/components/__tests__/AboutApp-test.tsx
@@ -0,0 +1,87 @@
+/*
+ * 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 { mount } from 'enzyme';
+import { AboutApp } from '../AboutApp';
+import { addWhitePageClass, removeWhitePageClass } from '../../../../helpers/pages';
+import { searchProjects } from '../../../../api/components';
+import { getFacet } from '../../../../api/issues';
+import { mockLocation, mockAppState, mockCurrentUser } from '../../../../helpers/testMocks';
+import { waitAndUpdate } from '../../../../helpers/testUtils';
+
+jest.mock('../../../../helpers/pages', () => ({
+ addWhitePageClass: jest.fn(),
+ removeWhitePageClass: jest.fn()
+}));
+
+jest.mock('../../../../api/components', () => ({
+ searchProjects: jest.fn().mockResolvedValue(5)
+}));
+
+jest.mock('../../../../api/issues', () => ({
+ getFacet: jest
+ .fn()
+ .mockResolvedValue([
+ { facet: { count: 5, val: 'CODE_SMELL' } },
+ { facet: { count: 10, val: 'BUG' } },
+ { facet: { count: 0, val: 'VULNERABILITY' } }
+ ])
+}));
+
+jest.mock('../../../../app/components/GlobalContainer', () => ({
+ default: class GlobalContainer extends React.Component {
+ static displayName = 'GlobalContainer';
+ render() {
+ return this.props.children;
+ }
+ }
+}));
+
+it('should render correctly', async () => {
+ const wrapper = mountRender();
+ await waitAndUpdate(wrapper);
+
+ expect(wrapper).toMatchSnapshot();
+ expect(addWhitePageClass).toBeCalled();
+
+ wrapper.unmount();
+ expect(removeWhitePageClass).toBeCalled();
+});
+
+it('should load issues, projects, and custom text upon mounting', () => {
+ const fetchAboutPageSettings = jest.fn();
+ mountRender({ fetchAboutPageSettings });
+ expect(fetchAboutPageSettings).toBeCalled();
+ expect(searchProjects).toBeCalled();
+ expect(getFacet).toBeCalled();
+});
+
+function mountRender(props: Partial<AboutApp['props']> = {}) {
+ return mount(
+ <AboutApp
+ appState={mockAppState()}
+ currentUser={mockCurrentUser()}
+ customText="Lorem ipsum"
+ fetchAboutPageSettings={jest.fn()}
+ location={mockLocation()}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/about/components/__tests__/__snapshots__/AboutApp-test.tsx.snap b/server/sonar-web/src/main/js/apps/about/components/__tests__/__snapshots__/AboutApp-test.tsx.snap
new file mode 100644
index 00000000000..c4a8c0e54b4
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/about/components/__tests__/__snapshots__/AboutApp-test.tsx.snap
@@ -0,0 +1,1253 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<AboutApp
+ appState={
+ Object {
+ "defaultOrganization": "foo",
+ "edition": "community",
+ "productionDatabase": true,
+ "qualifiers": Array [
+ "TRK",
+ ],
+ "settings": Object {},
+ "version": "1.0",
+ }
+ }
+ currentUser={
+ Object {
+ "isLoggedIn": false,
+ }
+ }
+ customText="Lorem ipsum"
+ fetchAboutPageSettings={
+ [MockFunction] {
+ "calls": Array [
+ Array [],
+ ],
+ "results": Array [
+ Object {
+ "isThrow": false,
+ "value": undefined,
+ },
+ ],
+ }
+ }
+ location={
+ Object {
+ "action": "PUSH",
+ "key": "key",
+ "pathname": "/path",
+ "query": Object {},
+ "search": "",
+ "state": Object {},
+ }
+ }
+>
+ <GlobalContainer
+ location={
+ Object {
+ "action": "PUSH",
+ "key": "key",
+ "pathname": "/path",
+ "query": Object {},
+ "search": "",
+ "state": Object {},
+ }
+ }
+ >
+ <div
+ className="page page-limited about-page"
+ id="about-page"
+ >
+ <A11ySkipTarget
+ anchor="about_main"
+ >
+ <A11ySkipTargetInner
+ addA11ySkipLink={[Function]}
+ anchor="about_main"
+ removeA11ySkipLink={[Function]}
+ >
+ <span
+ id="a11y_target__about_main"
+ />
+ </A11ySkipTargetInner>
+ </A11ySkipTarget>
+ <div
+ className="about-page-entry"
+ >
+ <div
+ className="about-page-intro"
+ >
+ <h1
+ className="big-spacer-bottom"
+ >
+ layout.sonar.slogan
+ </h1>
+ <Link
+ className="button button-active big-spacer-right"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/sessions/new"
+ >
+ <a
+ className="button button-active big-spacer-right"
+ onClick={[Function]}
+ style={Object {}}
+ >
+ layout.login
+ </a>
+ </Link>
+ <a
+ className="button"
+ href="https://redirect.sonarsource.com/doc/home.html"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ about_page.read_documentation
+ </a>
+ </div>
+ <div
+ className="about-page-instance"
+ >
+ <AboutProjects
+ count={0}
+ loading={false}
+ >
+ <div
+ className="about-page-projects"
+ >
+ <div>
+ <div>
+ <Link
+ className="about-page-projects-link"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/projects"
+ >
+ <a
+ className="about-page-projects-link"
+ onClick={[Function]}
+ style={Object {}}
+ >
+ 0
+ </a>
+ </Link>
+ </div>
+ <div>
+ about_page.projects_analyzed
+ </div>
+ </div>
+ </div>
+ </AboutProjects>
+ <EntryIssueTypes
+ loading={false}
+ >
+ <div
+ className="about-page-projects"
+ >
+ <table
+ className="about-page-issue-types"
+ >
+ <tbody>
+ <tr>
+ <td
+ className="about-page-issue-type-number"
+ >
+ <Link
+ className="about-page-issue-type-link"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/issues",
+ "query": Object {
+ "resolved": "false",
+ "s": "CREATION_DATE",
+ "types": "BUG",
+ },
+ }
+ }
+ >
+ <a
+ className="about-page-issue-type-link"
+ onClick={[Function]}
+ style={Object {}}
+ />
+ </Link>
+ </td>
+ <td>
+ <span
+ className="little-spacer-right"
+ >
+ <BugIcon>
+ <Icon>
+ <svg
+ height={16}
+ style={
+ Object {
+ "clipRule": "evenodd",
+ "fillRule": "evenodd",
+ "strokeLinejoin": "round",
+ "strokeMiterlimit": 1.41421,
+ }
+ }
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={16}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ >
+ <path
+ d="M11 9h1.3l.5.8.8-.5-.8-1.3H11v-.3l2-2.3V3h-1v2l-1 1.2V5c-.1-.8-.7-1.5-1.4-1.9L11 1.8l-.7-.7-1.8 1.6-1.8-1.6-.7.7 1.5 1.3C6.7 3.5 6.1 4.2 6 5v1.1L5 5V3H4v2.3l2 2.3V8H4.2l-.7 1.2.8.5.4-.7H6v.3l-2 1.9V14h1v-2.4l1-1C6 12 7.1 13 8.4 13h.8c.7 0 1.4-.3 1.8-.9.3-.4.3-.9.2-1.4l.9.9V14h1v-2.8l-2-1.9V9zm-2 2H8V6h1v5z"
+ style={
+ Object {
+ "fill": "currentColor",
+ }
+ }
+ />
+ </svg>
+ </Icon>
+ </BugIcon>
+ </span>
+ issue.type.BUG.plural
+ </td>
+ </tr>
+ <tr>
+ <td
+ className="about-page-issue-type-number"
+ >
+ <Link
+ className="about-page-issue-type-link"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/issues",
+ "query": Object {
+ "resolved": "false",
+ "s": "CREATION_DATE",
+ "types": "VULNERABILITY",
+ },
+ }
+ }
+ >
+ <a
+ className="about-page-issue-type-link"
+ onClick={[Function]}
+ style={Object {}}
+ />
+ </Link>
+ </td>
+ <td>
+ <span
+ className="little-spacer-right"
+ >
+ <VulnerabilityIcon>
+ <Icon>
+ <svg
+ height={16}
+ style={
+ Object {
+ "clipRule": "evenodd",
+ "fillRule": "evenodd",
+ "strokeLinejoin": "round",
+ "strokeMiterlimit": 1.41421,
+ }
+ }
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={16}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ >
+ <path
+ d="M10.8 5H6V3.9a2.28 2.28 0 0 1 2-2.5 2.22 2.22 0 0 1 1.8 1.2.48.48 0 0 0 .7.2.48.48 0 0 0 .2-.7A3 3 0 0 0 8 .4a3.34 3.34 0 0 0-3 3.5v1.2a2.16 2.16 0 0 0-2 2.1v4.4a2.22 2.22 0 0 0 2.2 2.2h5.6a2.22 2.22 0 0 0 2.2-2.2V7.2A2.22 2.22 0 0 0 10.8 5zm-2.2 5.5v1.2H7.4v-1.2a1.66 1.66 0 0 1-1.1-1.6A1.75 1.75 0 0 1 8 7.2a1.71 1.71 0 0 1 .6 3.3z"
+ style={
+ Object {
+ "fill": "currentColor",
+ }
+ }
+ />
+ </svg>
+ </Icon>
+ </VulnerabilityIcon>
+ </span>
+ issue.type.VULNERABILITY.plural
+ </td>
+ </tr>
+ <tr>
+ <td
+ className="about-page-issue-type-number"
+ >
+ <Link
+ className="about-page-issue-type-link"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/issues",
+ "query": Object {
+ "resolved": "false",
+ "s": "CREATION_DATE",
+ "types": "CODE_SMELL",
+ },
+ }
+ }
+ >
+ <a
+ className="about-page-issue-type-link"
+ onClick={[Function]}
+ style={Object {}}
+ />
+ </Link>
+ </td>
+ <td>
+ <span
+ className="little-spacer-right"
+ >
+ <CodeSmellIcon>
+ <Icon>
+ <svg
+ height={16}
+ style={
+ Object {
+ "clipRule": "evenodd",
+ "fillRule": "evenodd",
+ "strokeLinejoin": "round",
+ "strokeMiterlimit": 1.41421,
+ }
+ }
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={16}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ >
+ <path
+ d="M8 2C4.7 2 2 4.7 2 8s2.7 6 6 6 6-2.7 6-6-2.7-6-6-6zm-.5 5.5h.9v.9h-.9v-.9zm-3.8.2c-.1 0-.2-.1-.2-.2 0-.4.1-1.2.6-2S5.3 4.2 5.6 4c.2 0 .3 0 .3.1l1.3 2.3c0 .1 0 .2-.1.2-.1.2-.2.3-.3.5-.1.2-.2.4-.2.5 0 .1-.1.2-.2.2l-2.7-.1zM9.9 12c-.3.2-1.1.5-2 .5-.9 0-1.7-.3-2-.5-.1 0-.1-.2-.1-.3l1.3-2.3c0-.1.1-.1.2-.1.2.1.3.1.5.1s.4 0 .5-.1c.1 0 .2 0 .2.1l1.3 2.3c.2.2.2.3.1.3zm2.5-4.1L9.7 8c-.1 0-.2-.1-.2-.2 0-.2-.1-.4-.2-.5 0-.1-.2-.3-.3-.4-.1 0-.1-.1-.1-.2l1.3-2.3c.1-.1.2-.1.3-.1.3.2 1 .7 1.5 1.5s.6 1.6.6 2c0 0-.1.1-.2.1z"
+ style={
+ Object {
+ "fill": "currentColor",
+ }
+ }
+ />
+ </svg>
+ </Icon>
+ </CodeSmellIcon>
+ </span>
+ issue.type.CODE_SMELL.plural
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </EntryIssueTypes>
+ </div>
+ </div>
+ <div
+ className="about-page-section"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "Lorem ipsum",
+ }
+ }
+ />
+ <AboutLanguages>
+ <div
+ className="boxed-group"
+ >
+ <h2>
+ about_page.languages
+ </h2>
+ <div
+ className="boxed-group-inner"
+ >
+ <p
+ className="about-page-text"
+ >
+ about_page.languages.text
+ </p>
+ <ul
+ className="about-page-languages"
+ >
+ <li
+ key="0"
+ >
+ <a
+ href="https://redirect.sonarsource.com/plugins/java.html"
+ >
+ Java
+ </a>
+ <br />
+ <a
+ href="https://redirect.sonarsource.com/plugins/vbnet.html"
+ >
+ VB.NET
+ </a>
+ </li>
+ <li
+ key="1"
+ >
+ <a
+ href="https://redirect.sonarsource.com/plugins/cpp.html"
+ >
+ C/C++
+ </a>
+ <br />
+ <a
+ href="https://redirect.sonarsource.com/plugins/plsql.html"
+ >
+ PL/SQL
+ </a>
+ </li>
+ <li
+ key="2"
+ >
+ <a
+ href="https://redirect.sonarsource.com/plugins/csharp.html"
+ >
+ C#
+ </a>
+ <br />
+ <a
+ href="https://redirect.sonarsource.com/plugins/tsql.html"
+ >
+ T-SQL
+ </a>
+ </li>
+ <li
+ key="3"
+ >
+ <a
+ href="https://redirect.sonarsource.com/plugins/cobol.html"
+ >
+ COBOL
+ </a>
+ <br />
+ <a
+ href="https://redirect.sonarsource.com/plugins/flex.html"
+ >
+ Flex
+ </a>
+ </li>
+ <li
+ key="4"
+ >
+ <a
+ href="https://redirect.sonarsource.com/plugins/abap.html"
+ >
+ ABAP
+ </a>
+ <br />
+ <a
+ href="https://redirect.sonarsource.com/plugins/python.html"
+ >
+ Python
+ </a>
+ </li>
+ <li
+ key="5"
+ >
+ <a
+ href="https://redirect.sonarsource.com/plugins/web.html"
+ >
+ HTML
+ </a>
+ <br />
+ <a
+ href="https://redirect.sonarsource.com/plugins/groovy.html"
+ >
+ Groovy
+ </a>
+ </li>
+ <li
+ key="6"
+ >
+ <a
+ href="https://redirect.sonarsource.com/plugins/rpg.html"
+ >
+ RPG
+ </a>
+ <br />
+ <a
+ href="https://redirect.sonarsource.com/plugins/php.html"
+ >
+ PHP
+ </a>
+ </li>
+ <li
+ key="7"
+ >
+ <a
+ href="https://redirect.sonarsource.com/plugins/javascript.html"
+ >
+ JavaScript
+ </a>
+ <br />
+ <a
+ href="https://redirect.sonarsource.com/plugins/swift.html"
+ >
+ Swift
+ </a>
+ </li>
+ <li
+ key="8"
+ >
+ <a
+ href="https://redirect.sonarsource.com/plugins/typescript.html"
+ >
+ TypeScript
+ </a>
+ <br />
+ <a
+ href="https://redirect.sonarsource.com/plugins/vb.html"
+ >
+ Visual Basic
+ </a>
+ </li>
+ <li
+ key="9"
+ >
+ <a
+ href="https://redirect.sonarsource.com/plugins/objectivec.html"
+ >
+ Objective C
+ </a>
+ <br />
+ <a
+ href="https://redirect.sonarsource.com/plugins/pli.html"
+ >
+ PL/I
+ </a>
+ </li>
+ <li
+ key="10"
+ >
+ <a
+ href="https://redirect.sonarsource.com/plugins/xml.html"
+ >
+ XML
+ </a>
+ <br />
+ </li>
+ </ul>
+ </div>
+ </div>
+ </AboutLanguages>
+ <AboutQualityModel>
+ <div
+ className="boxed-group about-quality-model"
+ >
+ <h2>
+ about_page.quality_model
+ </h2>
+ <div
+ className="boxed-group-inner clearfix"
+ >
+ <div
+ className="flex-columns"
+ >
+ <div
+ className="flex-column flex-column-third"
+ >
+ <div
+ className="pull-left little-spacer-right"
+ >
+ <BugIcon>
+ <Icon>
+ <svg
+ height={16}
+ style={
+ Object {
+ "clipRule": "evenodd",
+ "fillRule": "evenodd",
+ "strokeLinejoin": "round",
+ "strokeMiterlimit": 1.41421,
+ }
+ }
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={16}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ >
+ <path
+ d="M11 9h1.3l.5.8.8-.5-.8-1.3H11v-.3l2-2.3V3h-1v2l-1 1.2V5c-.1-.8-.7-1.5-1.4-1.9L11 1.8l-.7-.7-1.8 1.6-1.8-1.6-.7.7 1.5 1.3C6.7 3.5 6.1 4.2 6 5v1.1L5 5V3H4v2.3l2 2.3V8H4.2l-.7 1.2.8.5.4-.7H6v.3l-2 1.9V14h1v-2.4l1-1C6 12 7.1 13 8.4 13h.8c.7 0 1.4-.3 1.8-.9.3-.4.3-.9.2-1.4l.9.9V14h1v-2.8l-2-1.9V9zm-2 2H8V6h1v5z"
+ style={
+ Object {
+ "fill": "currentColor",
+ }
+ }
+ />
+ </svg>
+ </Icon>
+ </BugIcon>
+ </div>
+ <p
+ className="about-page-text overflow-hidden"
+ >
+ <strong>
+ issue.type.BUG.plural
+ </strong>
+
+ about_page.quality_model.bugs
+ </p>
+ </div>
+ <div
+ className="flex-column flex-column-third"
+ >
+ <div
+ className="pull-left little-spacer-right"
+ >
+ <VulnerabilityIcon>
+ <Icon>
+ <svg
+ height={16}
+ style={
+ Object {
+ "clipRule": "evenodd",
+ "fillRule": "evenodd",
+ "strokeLinejoin": "round",
+ "strokeMiterlimit": 1.41421,
+ }
+ }
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={16}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ >
+ <path
+ d="M10.8 5H6V3.9a2.28 2.28 0 0 1 2-2.5 2.22 2.22 0 0 1 1.8 1.2.48.48 0 0 0 .7.2.48.48 0 0 0 .2-.7A3 3 0 0 0 8 .4a3.34 3.34 0 0 0-3 3.5v1.2a2.16 2.16 0 0 0-2 2.1v4.4a2.22 2.22 0 0 0 2.2 2.2h5.6a2.22 2.22 0 0 0 2.2-2.2V7.2A2.22 2.22 0 0 0 10.8 5zm-2.2 5.5v1.2H7.4v-1.2a1.66 1.66 0 0 1-1.1-1.6A1.75 1.75 0 0 1 8 7.2a1.71 1.71 0 0 1 .6 3.3z"
+ style={
+ Object {
+ "fill": "currentColor",
+ }
+ }
+ />
+ </svg>
+ </Icon>
+ </VulnerabilityIcon>
+ </div>
+ <p
+ className="about-page-text overflow-hidden"
+ >
+ <strong>
+ issue.type.VULNERABILITY.plural
+ </strong>
+
+ about_page.quality_model.vulnerabilities
+ </p>
+ </div>
+ <div
+ className="flex-column flex-column-third"
+ >
+ <div
+ className="pull-left little-spacer-right"
+ >
+ <CodeSmellIcon>
+ <Icon>
+ <svg
+ height={16}
+ style={
+ Object {
+ "clipRule": "evenodd",
+ "fillRule": "evenodd",
+ "strokeLinejoin": "round",
+ "strokeMiterlimit": 1.41421,
+ }
+ }
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={16}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ >
+ <path
+ d="M8 2C4.7 2 2 4.7 2 8s2.7 6 6 6 6-2.7 6-6-2.7-6-6-6zm-.5 5.5h.9v.9h-.9v-.9zm-3.8.2c-.1 0-.2-.1-.2-.2 0-.4.1-1.2.6-2S5.3 4.2 5.6 4c.2 0 .3 0 .3.1l1.3 2.3c0 .1 0 .2-.1.2-.1.2-.2.3-.3.5-.1.2-.2.4-.2.5 0 .1-.1.2-.2.2l-2.7-.1zM9.9 12c-.3.2-1.1.5-2 .5-.9 0-1.7-.3-2-.5-.1 0-.1-.2-.1-.3l1.3-2.3c0-.1.1-.1.2-.1.2.1.3.1.5.1s.4 0 .5-.1c.1 0 .2 0 .2.1l1.3 2.3c.2.2.2.3.1.3zm2.5-4.1L9.7 8c-.1 0-.2-.1-.2-.2 0-.2-.1-.4-.2-.5 0-.1-.2-.3-.3-.4-.1 0-.1-.1-.1-.2l1.3-2.3c.1-.1.2-.1.3-.1.3.2 1 .7 1.5 1.5s.6 1.6.6 2c0 0-.1.1-.2.1z"
+ style={
+ Object {
+ "fill": "currentColor",
+ }
+ }
+ />
+ </svg>
+ </Icon>
+ </CodeSmellIcon>
+ </div>
+ <p
+ className="about-page-text overflow-hidden"
+ >
+ <strong>
+ issue.type.CODE_SMELL.plural
+ </strong>
+
+ about_page.quality_model.code_smells
+ </p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </AboutQualityModel>
+ <div
+ className="flex-columns"
+ >
+ <div
+ className="flex-column flex-column-half about-page-group-boxes"
+ >
+ <AboutCleanCode>
+ <div
+ className="boxed-group"
+ >
+ <h2>
+ about_page.clean_code
+ </h2>
+ <div
+ className="boxed-group-inner"
+ >
+ <p
+ className="about-page-text"
+ >
+ about_page.clean_code.text
+ </p>
+ <ReadMore
+ link="https://redirect.sonarsource.com/doc/issues.html"
+ >
+ <div
+ className="big-spacer-top"
+ >
+ <a
+ className="about-page-link-more"
+ href="https://redirect.sonarsource.com/doc/issues.html"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <span>
+ about_page.read_more
+ </span>
+ </a>
+ </div>
+ </ReadMore>
+ </div>
+ </div>
+ </AboutCleanCode>
+ </div>
+ <div
+ className="flex-column flex-column-half about-page-group-boxes"
+ >
+ <AboutLeakPeriod>
+ <div
+ className="boxed-group"
+ >
+ <h2>
+ about_page.fix_the_leak
+ </h2>
+ <div
+ className="boxed-group-inner"
+ >
+ <p
+ className="about-page-text"
+ >
+ about_page.fix_the_leak_on_new_code.text
+ </p>
+ <ReadMore
+ link="https://redirect.sonarsource.com/doc/fix-the-leak.html"
+ >
+ <div
+ className="big-spacer-top"
+ >
+ <a
+ className="about-page-link-more"
+ href="https://redirect.sonarsource.com/doc/fix-the-leak.html"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <span>
+ about_page.read_more
+ </span>
+ </a>
+ </div>
+ </ReadMore>
+ </div>
+ </div>
+ </AboutLeakPeriod>
+ </div>
+ </div>
+ <div
+ className="flex-columns"
+ >
+ <div
+ className="flex-column flex-column-half about-page-group-boxes"
+ >
+ <AboutQualityGates>
+ <div
+ className="boxed-group"
+ >
+ <h2>
+ about_page.quality_gates
+ </h2>
+ <div
+ className="boxed-group-inner"
+ >
+ <p
+ className="about-page-text"
+ >
+ about_page.quality_gates.text
+ </p>
+ <ReadMore
+ link="https://redirect.sonarsource.com/doc/quality-gates.html"
+ >
+ <div
+ className="big-spacer-top"
+ >
+ <a
+ className="about-page-link-more"
+ href="https://redirect.sonarsource.com/doc/quality-gates.html"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <span>
+ about_page.read_more
+ </span>
+ </a>
+ </div>
+ </ReadMore>
+ </div>
+ </div>
+ </AboutQualityGates>
+ </div>
+ <div
+ className="flex-column flex-column-half about-page-group-boxes"
+ >
+ <AboutStandards
+ appState={
+ Object {
+ "defaultOrganization": "foo",
+ "edition": "community",
+ "productionDatabase": true,
+ "qualifiers": Array [
+ "TRK",
+ ],
+ "settings": Object {},
+ "version": "1.0",
+ }
+ }
+ >
+ <div
+ className="boxed-group"
+ >
+ <h2>
+ about_page.standards
+ </h2>
+ <div
+ className="boxed-group-inner"
+ >
+ <p
+ className="about-page-text"
+ >
+ about_page.standards.text
+ </p>
+ <div
+ className="spacer-top"
+ >
+ <ul
+ className="list-inline"
+ >
+ <li>
+ <Link
+ className="link-with-icon"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/coding_rules",
+ "query": Object {
+ "tags": "misra",
+ },
+ }
+ }
+ >
+ <a
+ className="link-with-icon"
+ onClick={[Function]}
+ style={Object {}}
+ >
+ <TagsIcon>
+ <Icon>
+ <svg
+ height={16}
+ style={
+ Object {
+ "clipRule": "evenodd",
+ "fillRule": "evenodd",
+ "strokeLinejoin": "round",
+ "strokeMiterlimit": 1.41421,
+ }
+ }
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={16}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ >
+ <path
+ d="M4.303 5.36a.94.94 0 0 0-.944-.945.94.94 0 0 0-.944.944c0 .524.42.944.944.944a.94.94 0 0 0 .944-.944zm7.866 4.246a.95.95 0 0 1-.273.663l-3.62 3.627a.95.95 0 0 1-1.334 0L1.671 8.618C1.295 8.249 1 7.534 1 7.01V3.944A.95.95 0 0 1 1.944 3H5.01c.523 0 1.238.295 1.614.67l5.271 5.265a.98.98 0 0 1 .273.67zm2.831 0a.95.95 0 0 1-.273.663l-3.62 3.627a.98.98 0 0 1-.67.273c-.384 0-.575-.177-.826-.435l3.465-3.465a.95.95 0 0 0 0-1.334L7.805 3.67C7.429 3.295 6.714 3 6.19 3h1.651c.524 0 1.239.295 1.615.67l5.271 5.265a.98.98 0 0 1 .273.67z"
+ style={
+ Object {
+ "fill": "currentColor",
+ }
+ }
+ />
+ </svg>
+ </Icon>
+ </TagsIcon>
+ <span
+ className="little-spacer-left"
+ >
+ MISRA
+ </span>
+ </a>
+ </Link>
+ </li>
+ <li>
+ <Link
+ className="link-with-icon"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/coding_rules",
+ "query": Object {
+ "tags": "cert",
+ },
+ }
+ }
+ >
+ <a
+ className="link-with-icon"
+ onClick={[Function]}
+ style={Object {}}
+ >
+ <TagsIcon>
+ <Icon>
+ <svg
+ height={16}
+ style={
+ Object {
+ "clipRule": "evenodd",
+ "fillRule": "evenodd",
+ "strokeLinejoin": "round",
+ "strokeMiterlimit": 1.41421,
+ }
+ }
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={16}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ >
+ <path
+ d="M4.303 5.36a.94.94 0 0 0-.944-.945.94.94 0 0 0-.944.944c0 .524.42.944.944.944a.94.94 0 0 0 .944-.944zm7.866 4.246a.95.95 0 0 1-.273.663l-3.62 3.627a.95.95 0 0 1-1.334 0L1.671 8.618C1.295 8.249 1 7.534 1 7.01V3.944A.95.95 0 0 1 1.944 3H5.01c.523 0 1.238.295 1.614.67l5.271 5.265a.98.98 0 0 1 .273.67zm2.831 0a.95.95 0 0 1-.273.663l-3.62 3.627a.98.98 0 0 1-.67.273c-.384 0-.575-.177-.826-.435l3.465-3.465a.95.95 0 0 0 0-1.334L7.805 3.67C7.429 3.295 6.714 3 6.19 3h1.651c.524 0 1.239.295 1.615.67l5.271 5.265a.98.98 0 0 1 .273.67z"
+ style={
+ Object {
+ "fill": "currentColor",
+ }
+ }
+ />
+ </svg>
+ </Icon>
+ </TagsIcon>
+ <span
+ className="little-spacer-left"
+ >
+ CERT
+ </span>
+ </a>
+ </Link>
+ </li>
+ <li>
+ <Link
+ className="link-with-icon"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/coding_rules",
+ "query": Object {
+ "tags": "cwe",
+ },
+ }
+ }
+ >
+ <a
+ className="link-with-icon"
+ onClick={[Function]}
+ style={Object {}}
+ >
+ <TagsIcon>
+ <Icon>
+ <svg
+ height={16}
+ style={
+ Object {
+ "clipRule": "evenodd",
+ "fillRule": "evenodd",
+ "strokeLinejoin": "round",
+ "strokeMiterlimit": 1.41421,
+ }
+ }
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={16}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ >
+ <path
+ d="M4.303 5.36a.94.94 0 0 0-.944-.945.94.94 0 0 0-.944.944c0 .524.42.944.944.944a.94.94 0 0 0 .944-.944zm7.866 4.246a.95.95 0 0 1-.273.663l-3.62 3.627a.95.95 0 0 1-1.334 0L1.671 8.618C1.295 8.249 1 7.534 1 7.01V3.944A.95.95 0 0 1 1.944 3H5.01c.523 0 1.238.295 1.614.67l5.271 5.265a.98.98 0 0 1 .273.67zm2.831 0a.95.95 0 0 1-.273.663l-3.62 3.627a.98.98 0 0 1-.67.273c-.384 0-.575-.177-.826-.435l3.465-3.465a.95.95 0 0 0 0-1.334L7.805 3.67C7.429 3.295 6.714 3 6.19 3h1.651c.524 0 1.239.295 1.615.67l5.271 5.265a.98.98 0 0 1 .273.67z"
+ style={
+ Object {
+ "fill": "currentColor",
+ }
+ }
+ />
+ </svg>
+ </Icon>
+ </TagsIcon>
+ <span
+ className="little-spacer-left"
+ >
+ CWE
+ </span>
+ </a>
+ </Link>
+ </li>
+ <li>
+ <Link
+ className="link-with-icon"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/coding_rules",
+ "query": Object {
+ "tags": "owasp-a1,owasp-a2,owasp-a3,owasp-a4,owasp-a5,owasp-a6,owasp-a7,owasp-a8,owasp-a9,owasp-a10",
+ },
+ }
+ }
+ >
+ <a
+ className="link-with-icon"
+ onClick={[Function]}
+ style={Object {}}
+ >
+ <TagsIcon>
+ <Icon>
+ <svg
+ height={16}
+ style={
+ Object {
+ "clipRule": "evenodd",
+ "fillRule": "evenodd",
+ "strokeLinejoin": "round",
+ "strokeMiterlimit": 1.41421,
+ }
+ }
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={16}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ >
+ <path
+ d="M4.303 5.36a.94.94 0 0 0-.944-.945.94.94 0 0 0-.944.944c0 .524.42.944.944.944a.94.94 0 0 0 .944-.944zm7.866 4.246a.95.95 0 0 1-.273.663l-3.62 3.627a.95.95 0 0 1-1.334 0L1.671 8.618C1.295 8.249 1 7.534 1 7.01V3.944A.95.95 0 0 1 1.944 3H5.01c.523 0 1.238.295 1.614.67l5.271 5.265a.98.98 0 0 1 .273.67zm2.831 0a.95.95 0 0 1-.273.663l-3.62 3.627a.98.98 0 0 1-.67.273c-.384 0-.575-.177-.826-.435l3.465-3.465a.95.95 0 0 0 0-1.334L7.805 3.67C7.429 3.295 6.714 3 6.19 3h1.651c.524 0 1.239.295 1.615.67l5.271 5.265a.98.98 0 0 1 .273.67z"
+ style={
+ Object {
+ "fill": "currentColor",
+ }
+ }
+ />
+ </svg>
+ </Icon>
+ </TagsIcon>
+ <span
+ className="little-spacer-left"
+ >
+ OWASP Top 10
+ </span>
+ </a>
+ </Link>
+ </li>
+ <li>
+ <Link
+ className="link-with-icon"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/coding_rules",
+ "query": Object {
+ "tags": "sans-top25-porous,sans-top25-risky,sans-top25-insecure",
+ },
+ }
+ }
+ >
+ <a
+ className="link-with-icon"
+ onClick={[Function]}
+ style={Object {}}
+ >
+ <TagsIcon>
+ <Icon>
+ <svg
+ height={16}
+ style={
+ Object {
+ "clipRule": "evenodd",
+ "fillRule": "evenodd",
+ "strokeLinejoin": "round",
+ "strokeMiterlimit": 1.41421,
+ }
+ }
+ version="1.1"
+ viewBox="0 0 16 16"
+ width={16}
+ xmlSpace="preserve"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ >
+ <path
+ d="M4.303 5.36a.94.94 0 0 0-.944-.945.94.94 0 0 0-.944.944c0 .524.42.944.944.944a.94.94 0 0 0 .944-.944zm7.866 4.246a.95.95 0 0 1-.273.663l-3.62 3.627a.95.95 0 0 1-1.334 0L1.671 8.618C1.295 8.249 1 7.534 1 7.01V3.944A.95.95 0 0 1 1.944 3H5.01c.523 0 1.238.295 1.614.67l5.271 5.265a.98.98 0 0 1 .273.67zm2.831 0a.95.95 0 0 1-.273.663l-3.62 3.627a.98.98 0 0 1-.67.273c-.384 0-.575-.177-.826-.435l3.465-3.465a.95.95 0 0 0 0-1.334L7.805 3.67C7.429 3.295 6.714 3 6.19 3h1.651c.524 0 1.239.295 1.615.67l5.271 5.265a.98.98 0 0 1 .273.67z"
+ style={
+ Object {
+ "fill": "currentColor",
+ }
+ }
+ />
+ </svg>
+ </Icon>
+ </TagsIcon>
+ <span
+ className="little-spacer-left"
+ >
+ SANS Top 25
+ </span>
+ </a>
+ </Link>
+ </li>
+ </ul>
+ </div>
+ <ReadMore
+ link="https://redirect.sonarsource.com/doc/rules.html"
+ >
+ <div
+ className="big-spacer-top"
+ >
+ <a
+ className="about-page-link-more"
+ href="https://redirect.sonarsource.com/doc/rules.html"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <span>
+ about_page.read_more
+ </span>
+ </a>
+ </div>
+ </ReadMore>
+ </div>
+ </div>
+ </AboutStandards>
+ </div>
+ </div>
+ <AboutScanners>
+ <div
+ className="boxed-group"
+ >
+ <h2>
+ about_page.scanners
+ </h2>
+ <div
+ className="boxed-group-inner"
+ >
+ <p
+ className="about-page-text"
+ >
+ about_page.scanners.text
+ </p>
+ <div
+ className="about-page-analyzers"
+ >
+ <a
+ className="about-page-analyzer-box"
+ href="https://redirect.sonarsource.com/doc/install-configure-scanner.html"
+ key="sonarqube"
+ >
+ <img
+ alt="about_page.scanners.sonarqube"
+ height={60}
+ src="/images/scanner-logos/sonarqube.svg"
+ />
+ </a>
+ <a
+ className="about-page-analyzer-box"
+ href="https://redirect.sonarsource.com/doc/install-configure-scanner-msbuild.html"
+ key="msbuild"
+ >
+ <img
+ alt="about_page.scanners.msbuild"
+ height={60}
+ src="/images/scanner-logos/msbuild.svg"
+ />
+ </a>
+ <a
+ className="about-page-analyzer-box"
+ href="https://redirect.sonarsource.com/doc/install-configure-scanner-maven.html"
+ key="maven"
+ >
+ <img
+ alt="about_page.scanners.maven"
+ height={60}
+ src="/images/scanner-logos/maven.svg"
+ />
+ </a>
+ <a
+ className="about-page-analyzer-box"
+ href="https://redirect.sonarsource.com/doc/gradle.html"
+ key="gradle"
+ >
+ <img
+ alt="about_page.scanners.gradle"
+ height={60}
+ src="/images/scanner-logos/gradle.svg"
+ />
+ </a>
+ <a
+ className="about-page-analyzer-box"
+ href="https://redirect.sonarsource.com/plugins/jenkins.html"
+ key="jenkins"
+ >
+ <img
+ alt="about_page.scanners.jenkins"
+ height={60}
+ src="/images/scanner-logos/jenkins.svg"
+ />
+ </a>
+ <a
+ className="about-page-analyzer-box"
+ href="https://redirect.sonarsource.com/doc/install-configure-scanner-ant.html"
+ key="ant"
+ >
+ <img
+ alt="about_page.scanners.ant"
+ height={60}
+ src="/images/scanner-logos/ant.svg"
+ />
+ </a>
+ </div>
+ </div>
+ </div>
+ </AboutScanners>
+ </div>
+ </GlobalContainer>
+</AboutApp>
+`;
diff --git a/server/sonar-web/src/main/js/apps/account/components/Account.tsx b/server/sonar-web/src/main/js/apps/account/components/Account.tsx
index 0cb548b71ed..6ca884d44ce 100644
--- a/server/sonar-web/src/main/js/apps/account/components/Account.tsx
+++ b/server/sonar-web/src/main/js/apps/account/components/Account.tsx
@@ -34,7 +34,7 @@ interface Props {
customOrganizations?: boolean;
}
-class Account extends React.PureComponent<Props> {
+export class Account extends React.PureComponent<Props> {
componentDidMount() {
if (!this.props.currentUser.isLoggedIn) {
handleRequiredAuthentication();
diff --git a/server/sonar-web/src/main/js/apps/account/components/__tests__/Account-test.tsx b/server/sonar-web/src/main/js/apps/account/components/__tests__/Account-test.tsx
new file mode 100644
index 00000000000..f109395c50f
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/account/components/__tests__/Account-test.tsx
@@ -0,0 +1,43 @@
+/*
+ * 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 { Account } from '../Account';
+import { mockCurrentUser } from '../../../../helpers/testMocks';
+import handleRequiredAuthentication from '../../../../app/utils/handleRequiredAuthentication';
+
+jest.mock('../../../../app/utils/handleRequiredAuthentication', () => ({
+ default: jest.fn()
+}));
+
+it('should render correctly', () => {
+ const wrapper = shallowRender();
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should not render for anonymous user', () => {
+ const wrapper = shallowRender({ currentUser: mockCurrentUser({ isLoggedIn: false }) });
+ expect(wrapper.type()).toBe(null);
+ expect(handleRequiredAuthentication).toBeCalled();
+});
+
+function shallowRender(props: Partial<Account['props']> = {}) {
+ return shallow(<Account currentUser={mockCurrentUser({ isLoggedIn: true })} {...props} />);
+}
diff --git a/server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Account-test.tsx.snap b/server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Account-test.tsx.snap
new file mode 100644
index 00000000000..23c112c210b
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Account-test.tsx.snap
@@ -0,0 +1,36 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ id="account-page"
+>
+ <Suggestions
+ suggestions="account"
+ />
+ <HelmetWrapper
+ defaultTitle="my_account.page"
+ defer={true}
+ encodeSpecialCharacters={true}
+ titleTemplate="%s - my_account.page"
+ />
+ <A11ySkipTarget
+ anchor="account_main"
+ />
+ <header
+ className="account-header"
+ >
+ <div
+ className="account-container clearfix"
+ >
+ <UserCard
+ user={
+ Object {
+ "isLoggedIn": true,
+ }
+ }
+ />
+ <Nav />
+ </div>
+ </header>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap
index aa8bc5e708b..e5b6c398f32 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap
@@ -2,7 +2,7 @@
exports[`should display two facets 1`] = `
<div>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="measures_filters"
label="component_measures.skip_to_filters"
weight={10}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx
index 5ab45e611d6..0f9760727c9 100644
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx
+++ b/server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx
@@ -21,7 +21,6 @@ import * as React from 'react';
import { times } from 'lodash';
import { Location } from 'history';
import { shallow, mount } from 'enzyme';
-import { Provider } from 'react-redux';
import { CreateOrganization } from '../CreateOrganization';
import {
bindAlmOrganization,
@@ -37,9 +36,8 @@ import {
mockOrganizationWithAdminActions,
mockOrganizationWithAlm,
mockAlmOrganization,
- mockCurrentUser,
- mockLocation,
- mockStore
+ mockLoggedInUser,
+ mockLocation
} from '../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../helpers/testUtils';
@@ -84,7 +82,7 @@ jest.mock('../../../../helpers/storage', () => ({
remove: jest.fn()
}));
-const user = mockCurrentUser();
+const user = mockLoggedInUser();
const fooAlmOrganization = mockAlmOrganization({ personal: true });
const fooBarAlmOrganization = mockAlmOrganization({
avatar: 'https://avatars3.githubusercontent.com/u/37629810?v=4',
@@ -314,7 +312,7 @@ it('should bind org and redirect to org home when coming from org binding', asyn
.mockReturnValueOnce(orgKey); // For BIND_ORGANIZATION_KEY
const wrapper = mountRender({
- currentUser: mockCurrentUser({ ...user, externalProvider: 'github' }),
+ currentUser: mockLoggedInUser({ ...user, externalProvider: 'github' }),
location: mockLocation({ query: { installation_id } }),
router: mockRouter({ push })
});
@@ -328,9 +326,7 @@ it('should bind org and redirect to org home when coming from org binding', asyn
});
function mountRender(props: Partial<CreateOrganization['props']> = {}) {
- return mount<CreateOrganization>(
- <Provider store={mockStore()}>{createComponent(props)}</Provider>
- );
+ return mount<CreateOrganization>(createComponent(props));
}
function shallowRender(props: Partial<CreateOrganization['props']> = {}) {
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap
index 7223dbfa007..aa76ac05400 100644
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap
@@ -17,7 +17,7 @@ exports[`should render with auto personal organization bind page 2`] = `
<div
className="page page-limited huge-spacer-top huge-spacer-bottom"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="create_org_main"
/>
<header
@@ -98,7 +98,7 @@ exports[`should render with auto tab displayed 1`] = `
<div
className="page page-limited huge-spacer-top huge-spacer-bottom"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="create_org_main"
/>
<header
@@ -188,7 +188,7 @@ exports[`should render with auto tab selected and manual disabled 2`] = `
<div
className="page page-limited huge-spacer-top huge-spacer-bottom"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="create_org_main"
/>
<header
@@ -315,7 +315,7 @@ exports[`should render with manual tab displayed 1`] = `
<div
className="page page-limited huge-spacer-top huge-spacer-bottom"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="create_org_main"
/>
<header
@@ -375,7 +375,7 @@ exports[`should render with organization bind page 2`] = `
<div
className="page page-limited huge-spacer-top huge-spacer-bottom"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="create_org_main"
/>
<header
@@ -503,7 +503,7 @@ exports[`should switch tabs 1`] = `
<div
className="page page-limited huge-spacer-top huge-spacer-bottom"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="create_org_main"
/>
<header
diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx
new file mode 100644
index 00000000000..3df094a3191
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx
@@ -0,0 +1,51 @@
+/*
+ * 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 CreateProjectPage from '../CreateProjectPage';
+import { mockLocation, mockRouter } from '../../../../helpers/testMocks';
+import { isSonarCloud } from '../../../../helpers/system';
+
+jest.mock('../../../../helpers/system', () => ({
+ isSonarCloud: jest.fn().mockReturnValue(false)
+}));
+
+it('should render correctly for SonarQube', () => {
+ const wrapper = shallowRender();
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render correctly for SonarCloud', () => {
+ (isSonarCloud as jest.Mock).mockReturnValue(true);
+ const wrapper = shallowRender();
+ expect(wrapper).toMatchSnapshot();
+});
+
+function shallowRender(props = {}) {
+ return shallow(
+ <CreateProjectPage
+ location={mockLocation()}
+ params={{}}
+ router={mockRouter()}
+ routes={[]}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap
new file mode 100644
index 00000000000..f6dad80158a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap
@@ -0,0 +1,71 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly for SonarCloud 1`] = `
+<Fragment>
+ <A11ySkipTarget
+ anchor="create_project_main"
+ />
+ <Connect(withCurrentUser(whenLoggedIn(Connect(withUserOrganizations(Connect(CreateProjectPageSonarCloud))))))
+ location={
+ Object {
+ "action": "PUSH",
+ "key": "key",
+ "pathname": "/path",
+ "query": Object {},
+ "search": "",
+ "state": Object {},
+ }
+ }
+ params={Object {}}
+ router={
+ Object {
+ "createHref": [MockFunction],
+ "createPath": [MockFunction],
+ "go": [MockFunction],
+ "goBack": [MockFunction],
+ "goForward": [MockFunction],
+ "isActive": [MockFunction],
+ "push": [MockFunction],
+ "replace": [MockFunction],
+ "setRouteLeaveHook": [MockFunction],
+ }
+ }
+ routes={Array []}
+ />
+</Fragment>
+`;
+
+exports[`should render correctly for SonarQube 1`] = `
+<Fragment>
+ <A11ySkipTarget
+ anchor="create_project_main"
+ />
+ <Connect(withCurrentUser(whenLoggedIn(CreateProjectPageSonarQube)))
+ location={
+ Object {
+ "action": "PUSH",
+ "key": "key",
+ "pathname": "/path",
+ "query": Object {},
+ "search": "",
+ "state": Object {},
+ }
+ }
+ params={Object {}}
+ router={
+ Object {
+ "createHref": [MockFunction],
+ "createPath": [MockFunction],
+ "go": [MockFunction],
+ "goBack": [MockFunction],
+ "goForward": [MockFunction],
+ "isActive": [MockFunction],
+ "push": [MockFunction],
+ "replace": [MockFunction],
+ "setRouteLeaveHook": [MockFunction],
+ }
+ }
+ routes={Array []}
+ />
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx
new file mode 100644
index 00000000000..82d70d4876a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx
@@ -0,0 +1,89 @@
+/*
+ * 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 { addSideBarClass, removeSideBarClass } from '../../../../helpers/pages';
+import App from '../App';
+
+jest.mock('../../../../components/common/ScreenPositionHelper', () => ({
+ default: class ScreenPositionHelper extends React.Component<{
+ children: (pos: { top: number }) => React.ReactNode;
+ }> {
+ static displayName = 'ScreenPositionHelper';
+ render() {
+ return this.props.children({ top: 0 });
+ }
+ }
+}));
+
+jest.mock(
+ 'Docs/../static/SonarQubeNavigationTree.json',
+ () => [
+ {
+ title: 'SonarQube',
+ children: ['/lorem/ipsum/']
+ }
+ ],
+ { virtual: true }
+);
+
+jest.mock(
+ 'Docs/../static/SonarCloudNavigationTree.json',
+ () => [
+ {
+ title: 'SonarCloud',
+ children: ['/lorem/ipsum/']
+ }
+ ],
+ { virtual: true }
+);
+
+jest.mock('../../../../helpers/pages', () => ({
+ addSideBarClass: jest.fn(),
+ removeSideBarClass: jest.fn()
+}));
+
+jest.mock('../../pages', () => {
+ const { mockDocumentationEntry } = require.requireActual('../../../../helpers/testMocks');
+ return {
+ default: () => [mockDocumentationEntry()]
+ };
+});
+
+it('should render correctly', () => {
+ const wrapper = shallowRender();
+
+ expect(wrapper).toMatchSnapshot();
+ expect(addSideBarClass).toBeCalled();
+
+ expect(wrapper.find('ScreenPositionHelper').dive()).toMatchSnapshot();
+
+ wrapper.unmount();
+ expect(removeSideBarClass).toBeCalled();
+});
+
+it("should show a 404 if the page doesn't exist", () => {
+ const wrapper = shallowRender({ params: { splat: 'unknown' } });
+ expect(wrapper).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<App['props']> = {}) {
+ return shallow(<App params={{ splat: 'lorem/ipsum' }} {...props} />);
+}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap
new file mode 100644
index 00000000000..5537387b421
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap
@@ -0,0 +1,118 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="layout-page"
+>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="Lorem | documentation.page_title"
+ >
+ <meta
+ content="noindex nofollow"
+ name="robots"
+ />
+ </HelmetWrapper>
+ <ScreenPositionHelper
+ className="layout-page-side-outer"
+ >
+ <Component />
+ </ScreenPositionHelper>
+ <div
+ className="layout-page-main"
+ >
+ <div
+ className="layout-page-main-inner"
+ >
+ <div
+ className="boxed-group"
+ >
+ <A11ySkipTarget
+ anchor="documentation_main"
+ />
+ <DocMarkdownBlock
+ className="documentation-content cut-margins boxed-group-inner"
+ content="Lorem ipsum dolor sit amet fredum"
+ displayH1={true}
+ stickyToc={true}
+ />
+ </div>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly 2`] = `
+<div
+ className="layout-page-side"
+ style={
+ Object {
+ "top": 0,
+ }
+ }
+>
+ <div
+ className="layout-page-side-inner"
+ >
+ <div
+ className="layout-page-filters"
+ >
+ <div
+ className="documentation-page-header"
+ >
+ <A11ySkipTarget
+ anchor="documentation_menu"
+ label="documentation.skip_to_nav"
+ weight={10}
+ />
+ <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/documentation/"
+ >
+ <h1>
+ documentation.page
+ </h1>
+ </Link>
+ </div>
+ <Sidebar
+ pages={
+ Array [
+ Object {
+ "content": "Lorem ipsum dolor sit amet fredum",
+ "navTitle": undefined,
+ "relativeName": "Lorem",
+ "text": "Lorem ipsum dolor sit amet fredum",
+ "title": "Lorem",
+ "url": "/lorem/ipsum",
+ },
+ ]
+ }
+ splat="lorem/ipsum"
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should show a 404 if the page doesn't exist 1`] = `
+<Fragment>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="documentation.page_title"
+ >
+ <meta
+ content="noindex nofollow"
+ name="robots"
+ />
+ </HelmetWrapper>
+ <A11ySkipTarget
+ anchor="documentation_main"
+ />
+ <NotFound
+ withContainer={false}
+ />
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap
index 7247252f779..78bbd758aa1 100644
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap
@@ -12,7 +12,7 @@ exports[`should fetch members and render for non-admin 1`] = `
<Suggestions
suggestions="organization_members"
/>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="members_main"
/>
<MembersPageHeader
@@ -41,7 +41,7 @@ exports[`should fetch members and render for non-admin 2`] = `
<Suggestions
suggestions="organization_members"
/>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="members_main"
/>
<MembersPageHeader
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.tsx.snap
index 033ecba6e9f..324678b7dc9 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.tsx.snap
@@ -13,7 +13,7 @@ exports[`should render correctly 1`] = `
encodeSpecialCharacters={true}
title="project_activity.page"
/>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="activity_main"
/>
<ProjectActivityPageHeader
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap
index 09bb32b5c55..d41f0b2801d 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap
@@ -21,7 +21,7 @@ exports[`renders 1`] = `
<div
className="layout-page-main"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="projects_main"
/>
<div
@@ -166,7 +166,7 @@ exports[`renders 2`] = `
<div
className="layout-page-main"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="projects_main"
/>
<div
@@ -277,7 +277,7 @@ exports[`renders correctly empty organization 2`] = `
<div
className="layout-page-main"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="projects_main"
/>
<ContextConsumer>
@@ -308,7 +308,7 @@ exports[`renders correctly empty organization 3`] = `
<div
className="layout-page-main"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="projects_main"
/>
<div
diff --git a/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/App-test.tsx.snap
index 91094ac224e..2884f4f0c57 100644
--- a/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/App-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/App-test.tsx.snap
@@ -16,7 +16,7 @@ exports[`handle checkbox for cwe display 1`] = `
<header
className="page-header"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="security_main"
/>
<h1
@@ -102,7 +102,7 @@ exports[`handle checkbox for cwe display 2`] = `
<header
className="page-header"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="security_main"
/>
<h1
@@ -252,7 +252,7 @@ exports[`renders owaspTop10 1`] = `
<header
className="page-header"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="security_main"
/>
<h1
@@ -396,7 +396,7 @@ exports[`renders sansTop25 1`] = `
<header
className="page-header"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="security_main"
/>
<h1
@@ -482,7 +482,7 @@ exports[`renders with cwe 1`] = `
<header
className="page-header"
>
- <Connect(A11ySkipTarget)
+ <A11ySkipTarget
anchor="security_main"
/>
<h1
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.tsx b/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.tsx
index 31112b25bfd..70658e1779e 100644
--- a/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.tsx
+++ b/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.tsx
@@ -47,7 +47,7 @@ interface State {
domains: T.WebApi.Domain[];
}
-class WebApiApp extends React.PureComponent<Props, State> {
+export class WebApiApp extends React.PureComponent<Props, State> {
mounted = false;
state: State = { domains: [] };
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/__tests__/WebApiApp-test.tsx b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/WebApiApp-test.tsx
new file mode 100644
index 00000000000..626e2f76bb9
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/WebApiApp-test.tsx
@@ -0,0 +1,82 @@
+/*
+ * 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 { WebApiApp } from '../WebApiApp';
+import { fetchWebApi } from '../../../../api/web-api';
+import { addSideBarClass, removeSideBarClass } from '../../../../helpers/pages';
+import { mockLocation, mockRouter } from '../../../../helpers/testMocks';
+import { waitAndUpdate } from '../../../../helpers/testUtils';
+
+jest.mock('../../../../api/web-api', () => ({
+ fetchWebApi: jest.fn().mockResolvedValue([
+ {
+ actions: [],
+ description: 'foo',
+ internal: true,
+ path: 'foo/bar',
+ since: '1.0'
+ }
+ ])
+}));
+
+jest.mock('../../../../helpers/pages', () => ({
+ addSideBarClass: jest.fn(),
+ removeSideBarClass: jest.fn()
+}));
+
+jest.mock('../../../../components/common/ScreenPositionHelper', () => ({
+ default: class ScreenPositionHelper extends React.Component<{
+ children: (pos: { top: number }) => React.ReactNode;
+ }> {
+ static displayName = 'ScreenPositionHelper';
+ render() {
+ return this.props.children({ top: 0 });
+ }
+ }
+}));
+
+it('should render correctly', async () => {
+ (global as any).scrollTo = jest.fn();
+
+ const wrapper = shallowRender();
+
+ expect(addSideBarClass).toBeCalled();
+ expect(fetchWebApi).toBeCalled();
+
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+ expect(wrapper.find('ScreenPositionHelper').dive()).toMatchSnapshot();
+
+ wrapper.unmount();
+ expect(removeSideBarClass).toBeCalled();
+});
+
+function shallowRender(props: Partial<WebApiApp['props']> = {}) {
+ return shallow(
+ <WebApiApp
+ location={mockLocation()}
+ params={{ splat: 'foo/bar' }}
+ router={mockRouter()}
+ routes={[]}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/WebApiApp-test.tsx.snap b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/WebApiApp-test.tsx.snap
new file mode 100644
index 00000000000..db788e7b310
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/WebApiApp-test.tsx.snap
@@ -0,0 +1,119 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="layout-page"
+>
+ <Suggestions
+ suggestions="api_documentation"
+ />
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="api_documentation.page"
+ />
+ <ScreenPositionHelper
+ className="layout-page-side-outer"
+ >
+ <Component />
+ </ScreenPositionHelper>
+ <div
+ className="layout-page-main"
+ >
+ <div
+ className="layout-page-main-inner"
+ >
+ <Domain
+ domain={
+ Object {
+ "actions": Array [],
+ "deprecatedSince": undefined,
+ "description": "foo",
+ "internal": true,
+ "path": "foo/bar",
+ "since": "1.0",
+ }
+ }
+ key="foo/bar"
+ query={
+ Object {
+ "deprecated": false,
+ "internal": false,
+ "search": "",
+ }
+ }
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly 2`] = `
+<div
+ className="layout-page-side"
+ style={
+ Object {
+ "top": 0,
+ }
+ }
+>
+ <div
+ className="layout-page-side-inner"
+ >
+ <div
+ className="layout-page-filters"
+ >
+ <A11ySkipTarget
+ anchor="webapi_main"
+ />
+ <div
+ className="web-api-page-header"
+ >
+ <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/web_api/"
+ >
+ <h1>
+ api_documentation.page
+ </h1>
+ </Link>
+ </div>
+ <Search
+ onSearch={[Function]}
+ onToggleDeprecated={[Function]}
+ onToggleInternal={[Function]}
+ query={
+ Object {
+ "deprecated": false,
+ "internal": false,
+ "search": "",
+ }
+ }
+ />
+ <Menu
+ domains={
+ Array [
+ Object {
+ "actions": Array [],
+ "deprecatedSince": undefined,
+ "description": "foo",
+ "internal": true,
+ "path": "foo/bar",
+ "since": "1.0",
+ },
+ ]
+ }
+ query={
+ Object {
+ "deprecated": false,
+ "internal": false,
+ "search": "",
+ }
+ }
+ splat="foo/bar"
+ />
+ </div>
+ </div>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/components/hoc/__tests__/whenLoggedIn-test.tsx b/server/sonar-web/src/main/js/components/hoc/__tests__/whenLoggedIn-test.tsx
index 147340ac776..967c3d8b1df 100644
--- a/server/sonar-web/src/main/js/components/hoc/__tests__/whenLoggedIn-test.tsx
+++ b/server/sonar-web/src/main/js/components/hoc/__tests__/whenLoggedIn-test.tsx
@@ -19,9 +19,9 @@
*/
import * as React from 'react';
import { shallow, ShallowWrapper } from 'enzyme';
-import { createStore } from 'redux';
import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
import { whenLoggedIn } from '../whenLoggedIn';
+import { mockStore } from '../../../helpers/testMocks';
jest.mock('../../../app/utils/handleRequiredAuthentication', () => ({
default: jest.fn()
@@ -36,14 +36,11 @@ class X extends React.Component {
const UnderTest = whenLoggedIn(X);
it('should render for logged in user', () => {
- const store = createStore(state => state, { users: { currentUser: { isLoggedIn: true } } });
- const wrapper = shallow(<UnderTest />, { context: { store } });
- expect(getRenderedType(wrapper)).toBe(X);
+ expect(getRenderedType(shallowRender())).toBe(X);
});
it('should not render for anonymous user', () => {
- const store = createStore(state => state, { users: { currentUser: { isLoggedIn: false } } });
- const wrapper = shallow(<UnderTest />, { context: { store } });
+ const wrapper = shallowRender(false);
expect(getRenderedType(wrapper)).toBe(null);
expect(handleRequiredAuthentication).toBeCalled();
});
@@ -54,3 +51,9 @@ function getRenderedType(wrapper: ShallowWrapper) {
.dive()
.type();
}
+
+function shallowRender(isLoggedIn = true) {
+ return shallow(<UnderTest />, {
+ context: { store: mockStore({ users: { currentUser: { isLoggedIn } } }) }
+ });
+}
diff --git a/server/sonar-web/src/main/js/components/hoc/__tests__/withCurrentUser-test.tsx b/server/sonar-web/src/main/js/components/hoc/__tests__/withCurrentUser-test.tsx
index d9f819a3485..2a379a3423d 100644
--- a/server/sonar-web/src/main/js/components/hoc/__tests__/withCurrentUser-test.tsx
+++ b/server/sonar-web/src/main/js/components/hoc/__tests__/withCurrentUser-test.tsx
@@ -19,8 +19,8 @@
*/
import * as React from 'react';
import { shallow } from 'enzyme';
-import { createStore } from 'redux';
import { withCurrentUser } from '../withCurrentUser';
+import { mockStore } from '../../../helpers/testMocks';
class X extends React.Component<{ currentUser: T.CurrentUser }> {
render() {
@@ -32,8 +32,9 @@ const UnderTest = withCurrentUser(X);
it('should pass logged in user', () => {
const currentUser = { isLoggedIn: false };
- const store = createStore(state => state, { users: { currentUser } });
- const wrapper = shallow(<UnderTest />, { context: { store } });
+ const wrapper = shallow(<UnderTest />, {
+ context: { store: mockStore({ users: { currentUser } }) }
+ });
expect(wrapper.dive().type()).toBe(X);
expect(wrapper.dive().prop('currentUser')).toBe(currentUser);
});
diff --git a/server/sonar-web/src/main/js/components/hoc/__tests__/withUserOrganizations-test.tsx b/server/sonar-web/src/main/js/components/hoc/__tests__/withUserOrganizations-test.tsx
index 72850e444d9..72f025bad08 100644
--- a/server/sonar-web/src/main/js/components/hoc/__tests__/withUserOrganizations-test.tsx
+++ b/server/sonar-web/src/main/js/components/hoc/__tests__/withUserOrganizations-test.tsx
@@ -19,8 +19,8 @@
*/
import * as React from 'react';
import { shallow } from 'enzyme';
-import { createStore } from 'redux';
import { withUserOrganizations } from '../withUserOrganizations';
+import { mockStore } from '../../../helpers/testMocks';
jest.mock('../../../api/organizations', () => ({ getOrganizations: jest.fn() }));
@@ -37,10 +37,14 @@ const UnderTest = withUserOrganizations(X);
it('should pass user organizations and logged in user', () => {
const org = { key: 'my-org', name: 'My Organization' };
- const store = createStore(state => state, {
- organizations: { byKey: { 'my-org': org }, my: ['my-org'] }
+ const wrapper = shallow(<UnderTest />, {
+ context: {
+ store: mockStore({
+ organizations: { byKey: { 'my-org': org }, my: ['my-org'] }
+ })
+ },
+ disableLifecycleMethods: true
});
- const wrapper = shallow(<UnderTest />, { context: { store }, disableLifecycleMethods: true });
const wrappedComponent = wrapper.dive();
expect(wrappedComponent.type()).toBe(X);
expect(wrappedComponent.prop('userOrganizations')).toEqual([org]);
diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts
index 5a1ff87a358..a14df2435cc 100644
--- a/server/sonar-web/src/main/js/helpers/testMocks.ts
+++ b/server/sonar-web/src/main/js/helpers/testMocks.ts
@@ -18,10 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { InjectedRouter } from 'react-router';
-import { Store } from 'redux';
+import { Store, createStore } from 'redux';
import { Location } from 'history';
import { ParsedAnalysis } from '../apps/projectActivity/utils';
import { Profile } from '../apps/quality-profiles/types';
+import { DocumentationEntry } from '../apps/documentation/utils';
export function mockAlmApplication(overrides: Partial<T.AlmApplication> = {}): T.AlmApplication {
return {
@@ -369,12 +370,20 @@ export function mockLongLivingBranch(
};
}
-export function mockStore(overrides: Partial<Store> = {}): Store {
+export function mockStore(state: any = {}, reducer = (state: any) => state): Store {
+ return createStore(reducer, state);
+}
+
+export function mockDocumentationEntry(
+ overrides: Partial<DocumentationEntry> = {}
+): DocumentationEntry {
return {
- dispatch: jest.fn(),
- getState: jest.fn(),
- subscribe: jest.fn(),
- replaceReducer: jest.fn(),
+ content: 'Lorem ipsum dolor sit amet fredum',
+ relativeName: 'Lorem',
+ navTitle: undefined,
+ text: 'Lorem ipsum dolor sit amet fredum',
+ title: 'Lorem',
+ url: '/lorem/ipsum',
...overrides
};
}