From 51cfe7eed3fa9e659f5e9e98d3e3ba9b9f0a6699 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Fri, 15 Mar 2019 10:38:59 +0100 Subject: [PATCH] SONAR-11681 Add loader for issue list --- .../js/apps/issues/__tests__/utils-test.ts | 57 ++++++++ .../main/js/apps/issues/components/App.tsx | 10 +- .../js/apps/issues/components/IssuesList.tsx | 33 ++++- .../components/__tests__/IssuesList-test.tsx | 54 +++++++ .../__snapshots__/IssuesList-test.tsx.snap | 133 ++++++++++++++++++ .../src/main/js/apps/issues/utils.ts | 8 ++ 6 files changed, 286 insertions(+), 9 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/issues/__tests__/utils-test.ts create mode 100644 server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesList-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesList-test.tsx.snap diff --git a/server/sonar-web/src/main/js/apps/issues/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/issues/__tests__/utils-test.ts new file mode 100644 index 00000000000..5b3528a60b2 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/issues/__tests__/utils-test.ts @@ -0,0 +1,57 @@ +/* + * 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 { scrollToElement } from '../../../helpers/scrolling'; +import { scrollToIssue } from '../utils'; + +jest.mock('../../../helpers/scrolling', () => ({ + scrollToElement: jest.fn() +})); + +beforeEach(() => { + jest.clearAllMocks(); +}); + +describe('scrollToIssue', () => { + it('should scroll to the issue', () => { + document.querySelector = jest.fn(() => ({})); + + scrollToIssue('issue1', false); + expect(scrollToElement).toHaveBeenCalled(); + }); + it("should ignore issue if it doesn't exist", () => { + document.querySelector = jest.fn(() => null); + + scrollToIssue('issue1', false); + expect(scrollToElement).not.toHaveBeenCalled(); + }); + it('should scroll smoothly by default', () => { + document.querySelector = jest.fn(() => ({})); + + scrollToIssue('issue1'); + expect(scrollToElement).toHaveBeenCalledWith( + {}, + { + bottomOffset: 100, + smooth: true, + topOffset: 250 + } + ); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/issues/components/App.tsx b/server/sonar-web/src/main/js/apps/issues/components/App.tsx index 6219650e84a..632211d2af7 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/App.tsx @@ -50,7 +50,8 @@ import { saveMyIssues, serializeQuery, STANDARDS, - ReferencedRule + ReferencedRule, + scrollToIssue } from '../utils'; import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget'; import { Alert } from '../../../components/ui/Alert'; @@ -78,7 +79,6 @@ import { removeSideBarClass, removeWhitePageClass } from '../../../helpers/pages'; -import { scrollToElement } from '../../../helpers/scrolling'; import { isSonarCloud } from '../../../helpers/system'; import { withRouter, Location, Router } from '../../../components/hoc/withRouter'; import '../../../components/search-navigator.css'; @@ -381,7 +381,6 @@ export class App extends React.PureComponent { open: undefined } }); - this.scrollToSelectedIssue(false); } }; @@ -395,10 +394,7 @@ export class App extends React.PureComponent { scrollToSelectedIssue = (smooth = true) => { const { selected } = this.state; if (selected) { - const element = document.querySelector(`[data-issue="${selected}"]`); - if (element) { - scrollToElement(element, { topOffset: 250, bottomOffset: 100, smooth }); - } + scrollToIssue(selected, smooth); } }; diff --git a/server/sonar-web/src/main/js/apps/issues/components/IssuesList.tsx b/server/sonar-web/src/main/js/apps/issues/components/IssuesList.tsx index da62b8a436c..66fec76a000 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/IssuesList.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/IssuesList.tsx @@ -19,7 +19,7 @@ */ import * as React from 'react'; import ListItem from './ListItem'; -import { Query } from '../utils'; +import { Query, scrollToIssue } from '../utils'; interface Props { branchLike: T.BranchLike | undefined; @@ -36,9 +36,38 @@ interface Props { selectedIssue: T.Issue | undefined; } -export default class IssuesList extends React.PureComponent { +interface State { + prerender: boolean; +} + +export default class IssuesList extends React.PureComponent { + state: State = { + prerender: true + }; + + componentDidMount() { + // ! \\ This prerender state variable is to enable the page to be displayed + // immediately, displaying a loader before attempting to render the + // list of issues. See https://jira.sonarsource.com/browse/SONAR-11681 + setTimeout(() => { + this.setState({ prerender: false }); + if (this.props.selectedIssue) { + scrollToIssue(this.props.selectedIssue.key, false); + } + }, 42); + } + render() { const { branchLike, checked, component, issues, openPopup, selectedIssue } = this.props; + const { prerender } = this.state; + + if (prerender) { + return ( +
+ +
+ ); + } return (
diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesList-test.tsx b/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesList-test.tsx new file mode 100644 index 00000000000..556824173d2 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesList-test.tsx @@ -0,0 +1,54 @@ +/* + * 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 IssuesList from '../IssuesList'; +import { mockIssue } from '../../../../helpers/testMocks'; +import { waitAndUpdate } from '../../../../helpers/testUtils'; + +it('should render correctly', async () => { + jest.useFakeTimers(); + + const wrapper = shallowRender(); + expect(wrapper).toMatchSnapshot(); + jest.runAllTimers(); + await waitAndUpdate(wrapper); + expect(wrapper).toMatchSnapshot(); +}); + +function shallowRender(overrides: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesList-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesList-test.tsx.snap new file mode 100644 index 00000000000..c7a30dd2379 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesList-test.tsx.snap @@ -0,0 +1,133 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` +
+ +
+`; + +exports[`should render correctly 2`] = ` +
+ + +
+`; diff --git a/server/sonar-web/src/main/js/apps/issues/utils.ts b/server/sonar-web/src/main/js/apps/issues/utils.ts index a64a653fa86..1f5e3e31e03 100644 --- a/server/sonar-web/src/main/js/apps/issues/utils.ts +++ b/server/sonar-web/src/main/js/apps/issues/utils.ts @@ -33,6 +33,7 @@ import { serializeDateShort, RawQuery } from '../../helpers/query'; +import { scrollToElement } from '../../helpers/scrolling'; export interface Query { assigned: boolean; @@ -267,3 +268,10 @@ export function allLocationsEmpty( ) { return getLocations(issue, selectedFlowIndex).every(location => !location.msg); } + +export function scrollToIssue(issue: string, smooth = true) { + const element = document.querySelector(`[data-issue="${issue}"]`); + if (element) { + scrollToElement(element, { topOffset: 250, bottomOffset: 100, smooth }); + } +} -- 2.39.5