]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-17163 Preserve comment when reviewing hotspots
authorGuillaume Peoc'h <guillaume.peoch@sonarsource.com>
Wed, 28 Sep 2022 07:58:31 +0000 (09:58 +0200)
committerPhilippe Perrin <philippe.perrin@sonarsource.com>
Fri, 7 Oct 2022 10:13:56 +0000 (12:13 +0200)
server/sonar-web/src/main/js/api/mocks/SecurityHotspotServiceMock.ts [new file with mode: 0644]
server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsApp-it.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/status/StatusSelection.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/status/StatusSelectionRenderer.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/Status-test.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/StatusSelection-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/StatusSelectionRenderer-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/Status-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/StatusSelection-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/StatusSelectionRenderer-test.tsx.snap [deleted file]

diff --git a/server/sonar-web/src/main/js/api/mocks/SecurityHotspotServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SecurityHotspotServiceMock.ts
new file mode 100644 (file)
index 0000000..0cc1900
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { cloneDeep, pick, range, times } from 'lodash';
+import { mockHotspot, mockRawHotspot } from '../../helpers/mocks/security-hotspots';
+import { mockSourceLine } from '../../helpers/mocks/sources';
+import { mockRuleDetails } from '../../helpers/testMocks';
+import { BranchParameters } from '../../types/branch-like';
+import { Hotspot, HotspotResolution, HotspotStatus } from '../../types/security-hotspots';
+import { getSources } from '../components';
+import { getMeasures } from '../measures';
+import { getRuleDetails } from '../rules';
+import { getSecurityHotspotDetails, getSecurityHotspots } from '../security-hotspots';
+
+const NUMBER_OF_LINES = 20;
+const MAX_END_RANGE = 10;
+
+export default class SecurityHotspotServiceMock {
+  hotspots: Hotspot[];
+  rawHotspotKey: string[];
+
+  constructor() {
+    this.rawHotspotKey = Object.keys(mockRawHotspot());
+    this.hotspots = [
+      mockHotspot({ key: '1', status: HotspotStatus.TO_REVIEW }),
+      mockHotspot({ key: '2', status: HotspotStatus.TO_REVIEW })
+    ];
+
+    (getMeasures as jest.Mock).mockImplementation(this.handleGetMeasures);
+    (getSecurityHotspots as jest.Mock).mockImplementation(this.handleGetSecurityHotspots);
+    (getSecurityHotspotDetails as jest.Mock).mockImplementation(
+      this.handleGetSecurityHotspotDetails
+    );
+    (getRuleDetails as jest.Mock).mockResolvedValue({ rule: mockRuleDetails() });
+    (getSources as jest.Mock).mockResolvedValue(
+      times(NUMBER_OF_LINES, n =>
+        mockSourceLine({
+          line: n,
+          code: '  <span class="sym-35 sym">symbole</span>'
+        })
+      )
+    );
+  }
+
+  handleGetSources = (data: { key: string; from?: number; to?: number } & BranchParameters) => {
+    return this.reply(
+      range(data.from || 1, data.to || MAX_END_RANGE).map(line => mockSourceLine({ line }))
+    );
+  };
+
+  handleGetSecurityHotspots = (
+    data: {
+      projectKey: string;
+      p: number;
+      ps: number;
+      status?: HotspotStatus;
+      resolution?: HotspotResolution;
+      onlyMine?: boolean;
+      inNewCodePeriod?: boolean;
+    } & BranchParameters
+  ) => {
+    return this.reply({
+      paging: { pageIndex: 1, pageSize: data.ps, total: this.hotspots.length },
+      hotspots: this.hotspots.map(hotspot => pick(hotspot, this.rawHotspotKey)),
+      components: [
+        {
+          key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed:index.php',
+          qualifier: 'FIL',
+          name: 'index.php',
+          longName: 'index.php',
+          path: 'index.php'
+        },
+        {
+          key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
+          qualifier: 'TRK',
+          name: 'benflix',
+          longName: 'benflix'
+        }
+      ]
+    });
+  };
+
+  handleGetSecurityHotspotDetails = (securityHotspotKey: string) => {
+    const hotspot = this.hotspots.find(h => h.key === securityHotspotKey);
+
+    if (hotspot === undefined) {
+      return Promise.reject({
+        errors: [{ msg: `No security hotspot for key ${securityHotspotKey}` }]
+      });
+    }
+
+    return this.reply(hotspot);
+  };
+
+  handleGetMeasures = () => {
+    return this.reply([
+      {
+        component: {
+          key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
+          name: 'benflix',
+          qualifier: 'TRK',
+          measures: [{ metric: 'security_hotspots_reviewed', value: '0.0', bestValue: false }]
+        }
+      }
+    ]);
+  };
+
+  reply<T>(response: T): Promise<T> {
+    return Promise.resolve(cloneDeep(response));
+  }
+
+  reset = () => {
+    this.rawHotspotKey = Object.keys(mockRawHotspot());
+    this.hotspots = [
+      mockHotspot({ key: '1', status: HotspotStatus.TO_REVIEW }),
+      mockHotspot({ key: '2', status: HotspotStatus.TO_REVIEW })
+    ];
+  };
+}
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsApp-it.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsApp-it.tsx
new file mode 100644 (file)
index 0000000..9bff505
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 { screen, within } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import React from 'react';
+import { Route } from 'react-router-dom';
+import { byRole, byTestId } from 'testing-library-selector';
+import SecurityHotspotServiceMock from '../../../api/mocks/SecurityHotspotServiceMock';
+import { mockComponent } from '../../../helpers/mocks/component';
+import { mockLoggedInUser } from '../../../helpers/testMocks';
+import { renderAppWithComponentContext } from '../../../helpers/testReactTestingUtils';
+import SecurityHotspotsApp from '../SecurityHotspotsApp';
+
+jest.mock('../../../api/measures');
+jest.mock('../../../api/security-hotspots');
+jest.mock('../../../api/rules');
+jest.mock('../../../api/components');
+
+const ui = {
+  selectStatusButton: byRole('button', {
+    name: 'hotspots.status.select_status'
+  }),
+  panel: byTestId('security-hotspot-test')
+};
+
+let handler: SecurityHotspotServiceMock;
+
+beforeEach(() => {
+  handler = new SecurityHotspotServiceMock();
+});
+
+afterEach(() => {
+  handler.reset();
+});
+
+it('should remember the comment when toggling change status panel for the same security hotspot', async () => {
+  const user = userEvent.setup();
+  renderSecurityHotspotsApp();
+
+  await user.click(await ui.selectStatusButton.find());
+
+  const comment = 'This is a comment';
+
+  const commentSection = within(ui.panel.get()).getByRole('textbox');
+  await user.click(commentSection);
+  await user.keyboard(comment);
+
+  // Close the panel
+  await user.keyboard('{Escape}');
+  // Check panel is closed
+  expect(ui.panel.query()).not.toBeInTheDocument();
+
+  await user.click(await ui.selectStatusButton.find());
+
+  expect(await screen.findByText(comment)).toBeInTheDocument();
+});
+
+function renderSecurityHotspotsApp(navigateTo?: string) {
+  renderAppWithComponentContext(
+    'security_hotspots',
+    () => <Route path="security_hotspots" element={<SecurityHotspotsApp />} />,
+    {
+      navigateTo,
+      currentUser: mockLoggedInUser({
+        login: 'foo',
+        name: 'foo'
+      })
+    },
+    {
+      branchLikes: [],
+      onBranchesChange: jest.fn(),
+      onComponentChange: jest.fn(),
+      component: mockComponent({
+        key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
+        name: 'benflix'
+      })
+    }
+  );
+}
index eb075fb4aa6b0e3bd42c0a62ea3dc3cc32583b0a..94465cdbcb8a2790b89a1e8d9bd27a8e3b76b16c 100644 (file)
@@ -41,7 +41,13 @@ export interface StatusProps {
 
 export function Status(props: StatusProps) {
   const { currentUser, hotspot } = props;
+
   const [isOpen, setIsOpen] = React.useState(false);
+  const [comment, setComment] = React.useState('');
+
+  React.useEffect(() => {
+    setComment('');
+  }, [hotspot.key]);
 
   const statusOption = getStatusOptionFromStatusAndResolution(hotspot.status, hotspot.resolution);
   const readonly = !hotspot.canChangeStatus || !isLoggedIn(currentUser);
@@ -67,6 +73,8 @@ export function Status(props: StatusProps) {
                       await props.onStatusChange(status);
                       setIsOpen(false);
                     }}
+                    comment={comment}
+                    setComment={setComment}
                   />
                 </DropdownOverlay>
               }>
index 2bc87e4e4186248ff7a5b957ada975c720645649..0283504411014e521f13c09bc8f4d3dbda0432f2 100644 (file)
@@ -29,10 +29,11 @@ import StatusSelectionRenderer from './StatusSelectionRenderer';
 interface Props {
   hotspot: Hotspot;
   onStatusOptionChange: (statusOption: HotspotStatusOption) => Promise<void>;
+  comment: string;
+  setComment: (comment: string) => void;
 }
 
 interface State {
-  comment?: string;
   loading: boolean;
   initialStatus: HotspotStatusOption;
   selectedStatus: HotspotStatusOption;
@@ -69,12 +70,12 @@ export default class StatusSelection extends React.PureComponent<Props, State> {
   };
 
   handleCommentChange = (comment: string) => {
-    this.setState({ comment });
+    this.props.setComment(comment);
   };
 
   handleSubmit = () => {
-    const { hotspot } = this.props;
-    const { comment, initialStatus, selectedStatus } = this.state;
+    const { hotspot, comment } = this.props;
+    const { initialStatus, selectedStatus } = this.state;
 
     if (selectedStatus && selectedStatus !== initialStatus) {
       this.setState({ loading: true });
@@ -84,14 +85,17 @@ export default class StatusSelection extends React.PureComponent<Props, State> {
       })
         .then(async () => {
           await this.props.onStatusOptionChange(selectedStatus);
-          this.setState({ loading: false });
+          if (this.mounted) {
+            this.setState({ loading: false });
+          }
         })
         .catch(() => this.setState({ loading: false }));
     }
   };
 
   render() {
-    const { comment, initialStatus, loading, selectedStatus } = this.state;
+    const { comment } = this.props;
+    const { initialStatus, loading, selectedStatus } = this.state;
     const submitDisabled = selectedStatus === initialStatus;
 
     return (
index 4260f4cc978180fa5fbfde928acdb6ea6908853f..7db97ba0fdc5c3c4da8e6b0cd1bcbf97398a17d9 100644 (file)
@@ -55,7 +55,7 @@ export default function StatusSelectionRenderer(props: StatusSelectionRendererPr
   };
 
   return (
-    <div className="abs-width-400">
+    <div data-testid="security-hotspot-test" className="abs-width-400">
       <div className="big-padded">
         {renderOption(HotspotStatusOption.TO_REVIEW)}
         {renderOption(HotspotStatusOption.ACKNOWLEDGED)}
index 1c7df7ecb7c1039271b22b2801671cff1e143cdb..d684caae1a31e322bf0f37888dbc43e8f1dca459 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import { shallow } from 'enzyme';
 import * as React from 'react';
-import { DropdownOverlay } from '../../../../../components/controls/Dropdown';
-import Toggler from '../../../../../components/controls/Toggler';
 import { mockHotspot } from '../../../../../helpers/mocks/security-hotspots';
 import { mockCurrentUser } from '../../../../../helpers/testMocks';
-import { click } from '../../../../../helpers/testUtils';
-import { HotspotStatusOption } from '../../../../../types/security-hotspots';
 import { Status, StatusProps } from '../Status';
-import StatusSelection from '../StatusSelection';
 
-it('should render correctly', () => {
-  const wrapper = shallowRender();
-  expect(wrapper).toMatchSnapshot('closed');
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { setSecurityHotspotStatus } from '../../../../../api/security-hotspots';
+import { HotspotResolution, HotspotStatus } from '../../../../../types/security-hotspots';
 
-  click(wrapper.find('#status-trigger'));
-  expect(wrapper).toMatchSnapshot('open');
+jest.mock('../../../../../api/security-hotspots', () => ({
+  setSecurityHotspotStatus: jest.fn().mockResolvedValue({})
+}));
 
-  wrapper
-    .find(Toggler)
-    .props()
-    .onRequestClose();
-  expect(wrapper.find(DropdownOverlay).length).toBe(0);
+it('should properly deal with comment/status/submit events', async () => {
+  const hotspot = mockHotspot();
+  renderStatusSelection({ hotspot });
+  const user = userEvent.setup();
+  const comment = 'COMMENT-TEXT';
 
-  expect(shallowRender({ hotspot: mockHotspot({ canChangeStatus: false }) })).toMatchSnapshot(
-    'readonly'
+  await user.click(screen.getByRole('button', { name: 'hotspots.status.select_status' }));
+
+  await user.click(
+    screen.getByRole('radio', {
+      name: 'hotspots.status_option.SAFE hotspots.status_option.SAFE.description'
+    })
   );
+
+  await user.click(screen.getByRole('textbox'));
+  await user.keyboard(comment);
+
+  await user.click(screen.getByRole('button', { name: 'hotspots.status.change_status' }));
+
+  expect(setSecurityHotspotStatus).toBeCalledWith(hotspot.key, {
+    status: HotspotStatus.REVIEWED,
+    resolution: HotspotResolution.SAFE,
+    comment
+  });
 });
 
-it('should properly deal with status changes', () => {
-  const onStatusChange = jest.fn();
-  const wrapper = shallowRender({ onStatusChange });
+it('should open change status panel correctly', async () => {
+  renderStatusSelection();
+  const user = userEvent.setup();
+  expect(screen.queryByTestId('security-hotspot-test')).not.toBeInTheDocument();
+  await user.click(screen.getByRole('button', { name: 'hotspots.status.select_status' }));
+  expect(screen.getByTestId('security-hotspot-test')).toBeInTheDocument();
+});
+
+it('should disallow status change for hotspot that are readonly', () => {
+  renderStatusSelection({ hotspot: mockHotspot({ canChangeStatus: false }) });
+  expect(screen.getByRole('button')).toBeDisabled();
+});
 
-  click(wrapper.find('#status-trigger'));
-  wrapper
-    .find(Toggler)
-    .dive()
-    .find(StatusSelection)
-    .props()
-    .onStatusOptionChange(HotspotStatusOption.SAFE);
-  expect(onStatusChange).toHaveBeenCalled();
-  expect(wrapper.find(DropdownOverlay).length).toBe(0);
+it('should disallow status change for user that are not logged in', () => {
+  renderStatusSelection({ currentUser: mockCurrentUser({ isLoggedIn: false }) });
+  expect(screen.getByRole('button')).toBeDisabled();
 });
 
-function shallowRender(props?: Partial<StatusProps>) {
-  return shallow<StatusProps>(
+function renderStatusSelection(props?: Partial<StatusProps>) {
+  render(
     <Status
       currentUser={mockCurrentUser({ isLoggedIn: true })}
       hotspot={mockHotspot()}
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/StatusSelection-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/StatusSelection-test.tsx
deleted file mode 100644 (file)
index cc9ed3b..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { setSecurityHotspotStatus } from '../../../../../api/security-hotspots';
-import { mockHotspot } from '../../../../../helpers/mocks/security-hotspots';
-import { waitAndUpdate } from '../../../../../helpers/testUtils';
-import { HotspotStatus, HotspotStatusOption } from '../../../../../types/security-hotspots';
-import StatusSelection from '../StatusSelection';
-import StatusSelectionRenderer from '../StatusSelectionRenderer';
-
-jest.mock('../../../../../api/security-hotspots', () => ({
-  setSecurityHotspotStatus: jest.fn()
-}));
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should properly deal with comment/status/submit events', async () => {
-  const hotspot = mockHotspot();
-  const onStatusOptionChange = jest.fn();
-  const wrapper = shallowRender({ hotspot, onStatusOptionChange });
-
-  const newStatusOption = HotspotStatusOption.SAFE;
-  wrapper
-    .find(StatusSelectionRenderer)
-    .props()
-    .onStatusChange(newStatusOption);
-  expect(wrapper.state().selectedStatus).toBe(newStatusOption);
-  expect(wrapper.find(StatusSelectionRenderer).props().submitDisabled).toBe(false);
-
-  const newComment = 'TEST-COMMENT';
-  wrapper
-    .find(StatusSelectionRenderer)
-    .props()
-    .onCommentChange(newComment);
-  expect(wrapper.state().comment).toBe(newComment);
-
-  (setSecurityHotspotStatus as jest.Mock).mockResolvedValueOnce({});
-  wrapper
-    .find(StatusSelectionRenderer)
-    .props()
-    .onSubmit();
-  expect(setSecurityHotspotStatus).toHaveBeenCalledWith(hotspot.key, {
-    status: HotspotStatus.REVIEWED,
-    resolution: HotspotStatusOption.SAFE,
-    comment: newComment
-  });
-
-  await waitAndUpdate(wrapper);
-
-  expect(onStatusOptionChange).toHaveBeenCalledWith(newStatusOption);
-});
-
-function shallowRender(props?: Partial<StatusSelection['props']>) {
-  return shallow<StatusSelection>(
-    <StatusSelection hotspot={mockHotspot()} onStatusOptionChange={jest.fn()} {...props} />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/StatusSelectionRenderer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/StatusSelectionRenderer-test.tsx
deleted file mode 100644 (file)
index a7ef05e..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { SubmitButton } from '../../../../../components/controls/buttons';
-import Radio from '../../../../../components/controls/Radio';
-import { change, click } from '../../../../../helpers/testUtils';
-import { HotspotStatusOption } from '../../../../../types/security-hotspots';
-import StatusSelectionRenderer, { StatusSelectionRendererProps } from '../StatusSelectionRenderer';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-  expect(shallowRender({ loading: true })).toMatchSnapshot('loading');
-  expect(
-    shallowRender({ submitDisabled: true })
-      .find(SubmitButton)
-      .props().disabled
-  ).toBe(true);
-});
-
-it('should call proper callbacks on actions', () => {
-  const onCommentChange = jest.fn();
-  const onStatusChange = jest.fn();
-  const onSubmit = jest.fn();
-  const wrapper = shallowRender({ onCommentChange, onStatusChange, onSubmit });
-
-  change(wrapper.find('textarea'), 'TATA');
-  expect(onCommentChange).toHaveBeenCalledWith('TATA');
-
-  wrapper
-    .find(Radio)
-    .first()
-    .props()
-    .onCheck(HotspotStatusOption.SAFE);
-  expect(onStatusChange).toHaveBeenCalledWith(HotspotStatusOption.SAFE);
-
-  click(wrapper.find(SubmitButton));
-  expect(onSubmit).toHaveBeenCalled();
-});
-
-function shallowRender(props?: Partial<StatusSelectionRendererProps>) {
-  return shallow<StatusSelectionRendererProps>(
-    <StatusSelectionRenderer
-      comment="TEST-COMMENT"
-      loading={false}
-      onCommentChange={jest.fn()}
-      onStatusChange={jest.fn()}
-      onSubmit={jest.fn()}
-      selectedStatus={HotspotStatusOption.TO_REVIEW}
-      submitDisabled={false}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/Status-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/Status-test.tsx.snap
deleted file mode 100644 (file)
index d415cbc..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: closed 1`] = `
-<div
-  className="display-flex-row display-flex-end"
->
-  <StatusDescription
-    showTitle={true}
-    statusOption="FIXED"
-  />
-  <div
-    className="spacer-top"
-  >
-    <Tooltip
-      overlay={null}
-      placement="bottom"
-    >
-      <div
-        className="dropdown"
-      >
-        <Toggler
-          closeOnClickOutside={true}
-          closeOnEscape={true}
-          onRequestClose={[Function]}
-          open={false}
-          overlay={
-            <DropdownOverlay
-              noPadding={true}
-              placement="bottom"
-            >
-              <StatusSelection
-                hotspot={
-                  Object {
-                    "assignee": "assignee",
-                    "assigneeUser": Object {
-                      "active": true,
-                      "local": true,
-                      "login": "assignee",
-                      "name": "John Doe",
-                    },
-                    "author": "author",
-                    "authorUser": Object {
-                      "active": true,
-                      "local": true,
-                      "login": "author",
-                      "name": "John Doe",
-                    },
-                    "canChangeStatus": true,
-                    "changelog": Array [],
-                    "comment": Array [],
-                    "component": Object {
-                      "key": "hotspot-component",
-                      "longName": "Hotspot component long name",
-                      "name": "Hotspot Component",
-                      "path": "path/to/component",
-                      "qualifier": "FIL",
-                    },
-                    "creationDate": "2013-05-13T17:55:41+0200",
-                    "flows": Array [
-                      Object {
-                        "locations": Array [
-                          Object {
-                            "component": "main.js",
-                            "textRange": Object {
-                              "endLine": 2,
-                              "endOffset": 2,
-                              "startLine": 1,
-                              "startOffset": 1,
-                            },
-                          },
-                        ],
-                      },
-                    ],
-                    "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
-                    "line": 142,
-                    "message": "'3' is a magic number.",
-                    "project": Object {
-                      "key": "hotspot-component",
-                      "longName": "Hotspot component long name",
-                      "name": "Hotspot Component",
-                      "path": "path/to/component",
-                      "qualifier": "TRK",
-                    },
-                    "resolution": "FIXED",
-                    "rule": Object {
-                      "key": "squid:S2077",
-                      "name": "That rule",
-                      "securityCategory": "sql-injection",
-                      "vulnerabilityProbability": "HIGH",
-                    },
-                    "status": "REVIEWED",
-                    "textRange": Object {
-                      "endLine": 142,
-                      "endOffset": 83,
-                      "startLine": 142,
-                      "startOffset": 26,
-                    },
-                    "updateDate": "2013-05-13T17:55:42+0200",
-                    "users": Array [
-                      Object {
-                        "active": true,
-                        "local": true,
-                        "login": "assignee",
-                        "name": "John Doe",
-                      },
-                      Object {
-                        "active": true,
-                        "local": true,
-                        "login": "author",
-                        "name": "John Doe",
-                      },
-                    ],
-                  }
-                }
-                onStatusOptionChange={[Function]}
-              />
-            </DropdownOverlay>
-          }
-        >
-          <Button
-            className="dropdown-toggle big-spacer-left"
-            disabled={false}
-            id="status-trigger"
-            onClick={[Function]}
-          >
-            <span>
-              hotspots.status.select_status
-            </span>
-            <DropdownIcon
-              className="little-spacer-left"
-            />
-          </Button>
-        </Toggler>
-      </div>
-    </Tooltip>
-  </div>
-</div>
-`;
-
-exports[`should render correctly: open 1`] = `
-<div
-  className="display-flex-row display-flex-end"
->
-  <StatusDescription
-    showTitle={true}
-    statusOption="FIXED"
-  />
-  <div
-    className="spacer-top"
-  >
-    <Tooltip
-      overlay={null}
-      placement="bottom"
-    >
-      <div
-        className="dropdown"
-      >
-        <Toggler
-          closeOnClickOutside={true}
-          closeOnEscape={true}
-          onRequestClose={[Function]}
-          open={true}
-          overlay={
-            <DropdownOverlay
-              noPadding={true}
-              placement="bottom"
-            >
-              <StatusSelection
-                hotspot={
-                  Object {
-                    "assignee": "assignee",
-                    "assigneeUser": Object {
-                      "active": true,
-                      "local": true,
-                      "login": "assignee",
-                      "name": "John Doe",
-                    },
-                    "author": "author",
-                    "authorUser": Object {
-                      "active": true,
-                      "local": true,
-                      "login": "author",
-                      "name": "John Doe",
-                    },
-                    "canChangeStatus": true,
-                    "changelog": Array [],
-                    "comment": Array [],
-                    "component": Object {
-                      "key": "hotspot-component",
-                      "longName": "Hotspot component long name",
-                      "name": "Hotspot Component",
-                      "path": "path/to/component",
-                      "qualifier": "FIL",
-                    },
-                    "creationDate": "2013-05-13T17:55:41+0200",
-                    "flows": Array [
-                      Object {
-                        "locations": Array [
-                          Object {
-                            "component": "main.js",
-                            "textRange": Object {
-                              "endLine": 2,
-                              "endOffset": 2,
-                              "startLine": 1,
-                              "startOffset": 1,
-                            },
-                          },
-                        ],
-                      },
-                    ],
-                    "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
-                    "line": 142,
-                    "message": "'3' is a magic number.",
-                    "project": Object {
-                      "key": "hotspot-component",
-                      "longName": "Hotspot component long name",
-                      "name": "Hotspot Component",
-                      "path": "path/to/component",
-                      "qualifier": "TRK",
-                    },
-                    "resolution": "FIXED",
-                    "rule": Object {
-                      "key": "squid:S2077",
-                      "name": "That rule",
-                      "securityCategory": "sql-injection",
-                      "vulnerabilityProbability": "HIGH",
-                    },
-                    "status": "REVIEWED",
-                    "textRange": Object {
-                      "endLine": 142,
-                      "endOffset": 83,
-                      "startLine": 142,
-                      "startOffset": 26,
-                    },
-                    "updateDate": "2013-05-13T17:55:42+0200",
-                    "users": Array [
-                      Object {
-                        "active": true,
-                        "local": true,
-                        "login": "assignee",
-                        "name": "John Doe",
-                      },
-                      Object {
-                        "active": true,
-                        "local": true,
-                        "login": "author",
-                        "name": "John Doe",
-                      },
-                    ],
-                  }
-                }
-                onStatusOptionChange={[Function]}
-              />
-            </DropdownOverlay>
-          }
-        >
-          <Button
-            className="dropdown-toggle big-spacer-left"
-            disabled={false}
-            id="status-trigger"
-            onClick={[Function]}
-          >
-            <span>
-              hotspots.status.select_status
-            </span>
-            <DropdownIcon
-              className="little-spacer-left"
-            />
-          </Button>
-        </Toggler>
-      </div>
-    </Tooltip>
-  </div>
-</div>
-`;
-
-exports[`should render correctly: readonly 1`] = `
-<div
-  className="display-flex-row display-flex-end"
->
-  <StatusDescription
-    showTitle={true}
-    statusOption="FIXED"
-  />
-  <div
-    className="spacer-top"
-  >
-    <Tooltip
-      overlay="hotspots.status.cannot_change_status"
-      placement="bottom"
-    >
-      <div
-        className="dropdown"
-      >
-        <Toggler
-          closeOnClickOutside={true}
-          closeOnEscape={true}
-          onRequestClose={[Function]}
-          open={false}
-          overlay={
-            <DropdownOverlay
-              noPadding={true}
-              placement="bottom"
-            >
-              <StatusSelection
-                hotspot={
-                  Object {
-                    "assignee": "assignee",
-                    "assigneeUser": Object {
-                      "active": true,
-                      "local": true,
-                      "login": "assignee",
-                      "name": "John Doe",
-                    },
-                    "author": "author",
-                    "authorUser": Object {
-                      "active": true,
-                      "local": true,
-                      "login": "author",
-                      "name": "John Doe",
-                    },
-                    "canChangeStatus": false,
-                    "changelog": Array [],
-                    "comment": Array [],
-                    "component": Object {
-                      "key": "hotspot-component",
-                      "longName": "Hotspot component long name",
-                      "name": "Hotspot Component",
-                      "path": "path/to/component",
-                      "qualifier": "FIL",
-                    },
-                    "creationDate": "2013-05-13T17:55:41+0200",
-                    "flows": Array [
-                      Object {
-                        "locations": Array [
-                          Object {
-                            "component": "main.js",
-                            "textRange": Object {
-                              "endLine": 2,
-                              "endOffset": 2,
-                              "startLine": 1,
-                              "startOffset": 1,
-                            },
-                          },
-                        ],
-                      },
-                    ],
-                    "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
-                    "line": 142,
-                    "message": "'3' is a magic number.",
-                    "project": Object {
-                      "key": "hotspot-component",
-                      "longName": "Hotspot component long name",
-                      "name": "Hotspot Component",
-                      "path": "path/to/component",
-                      "qualifier": "TRK",
-                    },
-                    "resolution": "FIXED",
-                    "rule": Object {
-                      "key": "squid:S2077",
-                      "name": "That rule",
-                      "securityCategory": "sql-injection",
-                      "vulnerabilityProbability": "HIGH",
-                    },
-                    "status": "REVIEWED",
-                    "textRange": Object {
-                      "endLine": 142,
-                      "endOffset": 83,
-                      "startLine": 142,
-                      "startOffset": 26,
-                    },
-                    "updateDate": "2013-05-13T17:55:42+0200",
-                    "users": Array [
-                      Object {
-                        "active": true,
-                        "local": true,
-                        "login": "assignee",
-                        "name": "John Doe",
-                      },
-                      Object {
-                        "active": true,
-                        "local": true,
-                        "login": "author",
-                        "name": "John Doe",
-                      },
-                    ],
-                  }
-                }
-                onStatusOptionChange={[Function]}
-              />
-            </DropdownOverlay>
-          }
-        >
-          <Button
-            className="dropdown-toggle big-spacer-left"
-            disabled={true}
-            id="status-trigger"
-            onClick={[Function]}
-          >
-            <span>
-              hotspots.status.select_status
-            </span>
-            <DropdownIcon
-              className="little-spacer-left"
-            />
-          </Button>
-        </Toggler>
-      </div>
-    </Tooltip>
-  </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/StatusSelection-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/StatusSelection-test.tsx.snap
deleted file mode 100644 (file)
index 61d22f5..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<StatusSelectionRenderer
-  loading={false}
-  onCommentChange={[Function]}
-  onStatusChange={[Function]}
-  onSubmit={[Function]}
-  selectedStatus="FIXED"
-  submitDisabled={true}
-/>
-`;
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/StatusSelectionRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/StatusSelectionRenderer-test.tsx.snap
deleted file mode 100644 (file)
index d0f786c..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  className="abs-width-400"
->
-  <div
-    className="big-padded"
-  >
-    <Radio
-      alignLabel={true}
-      checked={true}
-      className="big-spacer-bottom status-radio"
-      onCheck={[MockFunction]}
-      value="TO_REVIEW"
-    >
-      <StatusDescription
-        statusInBadge={false}
-        statusOption="TO_REVIEW"
-      />
-    </Radio>
-    <Radio
-      alignLabel={true}
-      checked={false}
-      className="big-spacer-bottom status-radio"
-      onCheck={[MockFunction]}
-      value="ACKNOWLEDGED"
-    >
-      <StatusDescription
-        statusInBadge={false}
-        statusOption="ACKNOWLEDGED"
-      />
-    </Radio>
-    <Radio
-      alignLabel={true}
-      checked={false}
-      className="big-spacer-bottom status-radio"
-      onCheck={[MockFunction]}
-      value="FIXED"
-    >
-      <StatusDescription
-        statusInBadge={false}
-        statusOption="FIXED"
-      />
-    </Radio>
-    <Radio
-      alignLabel={true}
-      checked={false}
-      className="big-spacer-bottom status-radio"
-      onCheck={[MockFunction]}
-      value="SAFE"
-    >
-      <StatusDescription
-        statusInBadge={false}
-        statusOption="SAFE"
-      />
-    </Radio>
-  </div>
-  <hr />
-  <div
-    className="big-padded display-flex-column"
-  >
-    <label
-      className="text-bold"
-      htmlFor="comment-textarea"
-    >
-      hotspots.status.add_comment
-    </label>
-    <textarea
-      className="spacer-top form-field fixed-width spacer-bottom"
-      id="comment-textarea"
-      onChange={[Function]}
-      rows={4}
-      value="TEST-COMMENT"
-    />
-    <FormattingTips />
-    <div
-      className="big-spacer-top display-flex-justify-end display-flex-center"
-    >
-      <SubmitButton
-        disabled={false}
-        onClick={[MockFunction]}
-      >
-        hotspots.status.change_status
-      </SubmitButton>
-    </div>
-  </div>
-</div>
-`;
-
-exports[`should render correctly: loading 1`] = `
-<div
-  className="abs-width-400"
->
-  <div
-    className="big-padded"
-  >
-    <Radio
-      alignLabel={true}
-      checked={true}
-      className="big-spacer-bottom status-radio"
-      onCheck={[MockFunction]}
-      value="TO_REVIEW"
-    >
-      <StatusDescription
-        statusInBadge={false}
-        statusOption="TO_REVIEW"
-      />
-    </Radio>
-    <Radio
-      alignLabel={true}
-      checked={false}
-      className="big-spacer-bottom status-radio"
-      onCheck={[MockFunction]}
-      value="ACKNOWLEDGED"
-    >
-      <StatusDescription
-        statusInBadge={false}
-        statusOption="ACKNOWLEDGED"
-      />
-    </Radio>
-    <Radio
-      alignLabel={true}
-      checked={false}
-      className="big-spacer-bottom status-radio"
-      onCheck={[MockFunction]}
-      value="FIXED"
-    >
-      <StatusDescription
-        statusInBadge={false}
-        statusOption="FIXED"
-      />
-    </Radio>
-    <Radio
-      alignLabel={true}
-      checked={false}
-      className="big-spacer-bottom status-radio"
-      onCheck={[MockFunction]}
-      value="SAFE"
-    >
-      <StatusDescription
-        statusInBadge={false}
-        statusOption="SAFE"
-      />
-    </Radio>
-  </div>
-  <hr />
-  <div
-    className="big-padded display-flex-column"
-  >
-    <label
-      className="text-bold"
-      htmlFor="comment-textarea"
-    >
-      hotspots.status.add_comment
-    </label>
-    <textarea
-      className="spacer-top form-field fixed-width spacer-bottom"
-      id="comment-textarea"
-      onChange={[Function]}
-      rows={4}
-      value="TEST-COMMENT"
-    />
-    <FormattingTips />
-    <div
-      className="big-spacer-top display-flex-justify-end display-flex-center"
-    >
-      <SubmitButton
-        disabled={true}
-        onClick={[MockFunction]}
-      >
-        hotspots.status.change_status
-      </SubmitButton>
-      <i
-        className="spacer-left spinner"
-      />
-    </div>
-  </div>
-</div>
-`;