From 62a8287557d8ea46c6d09a9acd679f1e3c5f01cd Mon Sep 17 00:00:00 2001 From: Wouter Admiraal Date: Thu, 7 Mar 2019 13:30:28 +0100 Subject: [PATCH] Add tests for untested components --- .../js/app/components/GlobalContainer.tsx | 2 +- .../__tests__/GlobalContainer-test.tsx | 51 + .../__tests__/ProjectAdminContainer-test.tsx | 71 + .../GlobalContainer-test.tsx.snap | 41 + .../ProjectAdminContainer-test.tsx.snap | 40 + .../a11y/__tests__/A11yProvider-test.tsx | 7 +- .../js/apps/about/components/AboutApp.tsx | 2 +- .../components/__tests__/AboutApp-test.tsx | 87 ++ .../__snapshots__/AboutApp-test.tsx.snap | 1253 +++++++++++++++++ .../js/apps/account/components/Account.tsx | 2 +- .../components/__tests__/Account-test.tsx | 43 + .../__snapshots__/Account-test.tsx.snap | 36 + .../__snapshots__/Sidebar-test.tsx.snap | 2 +- .../__tests__/CreateOrganization-test.tsx | 14 +- .../CreateOrganization-test.tsx.snap | 12 +- .../__tests__/CreateProjectPage-test.tsx | 51 + .../CreateProjectPage-test.tsx.snap | 71 + .../components/__tests__/App-test.tsx | 89 ++ .../__tests__/__snapshots__/App-test.tsx.snap | 118 ++ .../OrganizationMembers-test.tsx.snap | 4 +- .../ProjectActivityApp-test.tsx.snap | 2 +- .../__snapshots__/AllProjects-test.tsx.snap | 8 +- .../__tests__/__snapshots__/App-test.tsx.snap | 10 +- .../js/apps/web-api/components/WebApiApp.tsx | 2 +- .../components/__tests__/WebApiApp-test.tsx | 82 ++ .../__snapshots__/WebApiApp-test.tsx.snap | 119 ++ .../hoc/__tests__/whenLoggedIn-test.tsx | 15 +- .../hoc/__tests__/withCurrentUser-test.tsx | 7 +- .../__tests__/withUserOrganizations-test.tsx | 12 +- .../src/main/js/helpers/testMocks.ts | 21 +- 30 files changed, 2220 insertions(+), 54 deletions(-) create mode 100644 server/sonar-web/src/main/js/app/components/__tests__/GlobalContainer-test.tsx create mode 100644 server/sonar-web/src/main/js/app/components/__tests__/ProjectAdminContainer-test.tsx create mode 100644 server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/ProjectAdminContainer-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/apps/about/components/__tests__/AboutApp-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/about/components/__tests__/__snapshots__/AboutApp-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/apps/account/components/__tests__/Account-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/account/components/__tests__/__snapshots__/Account-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/apps/web-api/components/__tests__/WebApiApp-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/WebApiApp-test.tsx.snap 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 = {}) { + class ChildComponent extends React.Component { + render() { + return null; + } + } + + return shallow( + + + + ); +} 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 = {}) { + return mount(createComponent(props)); +} + +function shallowRender(props: Partial = {}) { + return shallow(createComponent(props)); +} + +function createComponent(props: Partial = {}) { + return ( + + + + ); +} 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`] = ` + + + + +
+
+
+ + + + + +
+
+ +
+
+
+
+`; 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`] = ` + + + + +`; 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 { +export class AboutApp extends React.PureComponent { 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 = {}) { + return mount( + + ); +} 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`] = ` + + +
+ + + + + +
+ +
+ +
+
+
+ + + 0 + + +
+
+ about_page.projects_analyzed +
+
+
+
+ +
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + issue.type.BUG.plural +
+ + + + + + + + + + + + + + issue.type.VULNERABILITY.plural +
+ + + + + + + + + + + + + + issue.type.CODE_SMELL.plural +
+
+
+
+
+
+ + + + +
+

+ about_page.quality_model +

+
+
+
+
+ + + + + + + +
+

+ + issue.type.BUG.plural + + + about_page.quality_model.bugs +

+
+
+
+ + + + + + + +
+

+ + issue.type.VULNERABILITY.plural + + + about_page.quality_model.vulnerabilities +

+
+
+
+ + + + + + + +
+

+ + issue.type.CODE_SMELL.plural + + + about_page.quality_model.code_smells +

+
+
+
+
+
+
+
+ +
+

+ about_page.clean_code +

+
+

+ about_page.clean_code.text +

+ + + +
+
+
+
+
+ +
+

+ about_page.fix_the_leak +

+
+

+ about_page.fix_the_leak_on_new_code.text +

+ + + +
+
+
+
+
+
+
+ +
+

+ about_page.quality_gates +

+
+

+ about_page.quality_gates.text +

+ + + +
+
+
+
+
+ +
+

+ about_page.standards +

+ +
+
+
+
+ +
+

+ about_page.scanners +

+
+

+ about_page.scanners.text +

+ +
+
+
+
+ + +`; 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 { +export class Account extends React.PureComponent { 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 = {}) { + return shallow(); +} 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`] = ` +
+ + + +
+
+ +
+
+
+`; 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`] = `
- ({ 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 = {}) { - return mount( - {createComponent(props)} - ); + return mount(createComponent(props)); } function shallowRender(props: Partial = {}) { 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`] = `
-
-
-
-
-
-
({ + 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( + + ); +} 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`] = ` + + + + +`; + +exports[`should render correctly for SonarQube 1`] = ` + + + + +`; 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 = {}) { + return shallow(); +} 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`] = ` +
+ + + + + + +
+
+
+ + +
+
+
+
+`; + +exports[`should render correctly 2`] = ` +
+
+
+
+ + +

+ documentation.page +

+ +
+ +
+
+
+`; + +exports[`should show a 404 if the page doesn't exist 1`] = ` + + + + + + + +`; 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`] = ` - - - -
-
- @@ -308,7 +308,7 @@ exports[`renders correctly empty organization 3`] = `
-
-

-

-

-

-

{ +export class WebApiApp extends React.PureComponent { 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 = {}) { + return shallow( + + ); +} 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`] = ` +
+ + + + + +
+
+ +
+
+
+`; + +exports[`should render correctly 2`] = ` +
+
+
+ +
+ +

+ api_documentation.page +

+ +
+ + +
+
+
+`; 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(, { 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(, { 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(, { + 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(, { context: { store } }); + const wrapper = shallow(, { + 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(, { + context: { + store: mockStore({ + organizations: { byKey: { 'my-org': org }, my: ['my-org'] } + }) + }, + disableLifecycleMethods: true }); - const wrapper = shallow(, { 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 { return { @@ -369,12 +370,20 @@ export function mockLongLivingBranch( }; } -export function mockStore(overrides: Partial = {}): Store { +export function mockStore(state: any = {}, reducer = (state: any) => state): Store { + return createStore(reducer, state); +} + +export function mockDocumentationEntry( + overrides: Partial = {} +): 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 }; } -- 2.39.5