]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20473 Fix race condition on Measures page
authorDavid Cho-Lerat <david.cho-lerat@sonarsource.com>
Wed, 15 Nov 2023 10:58:19 +0000 (11:58 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 15 Nov 2023 20:02:39 +0000 (20:02 +0000)
server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx
server/sonar-web/src/main/js/apps/component-measures/components/ComponentMeasuresApp.tsx

index c34b4c991b349eddb38e653ef534d7cc16f5d2e6..46eaaba121abad4ced03d9c5d1f47592f5065735 100644 (file)
@@ -392,14 +392,14 @@ describe('redirects', () => {
 
   it('should redirect old metric route', async () => {
     const { ui } = getPageObject();
-    renderMeasuresApp('component_measures/metric/bugs');
+    renderMeasuresApp('component_measures/metric/bugs?id=foo');
     await ui.appLoaded();
     expect(ui.measureBtn('Bugs 0').get()).toHaveAttribute('aria-current', 'true');
   });
 
   it('should redirect old domain route', async () => {
     const { ui } = getPageObject();
-    renderMeasuresApp('component_measures/domain/bugs');
+    renderMeasuresApp('component_measures/domain/bugs?id=foo');
     await ui.appLoaded();
     expect(ui.reliabilityDomainBtn.get()).toHaveAttribute('aria-expanded', 'true');
   });
@@ -493,7 +493,7 @@ function getPageObject() {
     notShowingAllComponentsTxt: byText(/component_measures.hidden_best_score_metrics/),
 
     // Misc
-    loading: byLabelText('loading'),
+    loading: byText('loading'),
     breadcrumbLink: (name: string) => byRole('link', { name }),
     viewSelect: byLabelText('component_measures.view_as'),
     emptyText: byText('component_measures.empty'),
@@ -542,7 +542,7 @@ function getPageObject() {
 
 function renderMeasuresApp(navigateTo?: string, componentContext?: Partial<ComponentContextShape>) {
   return renderAppWithComponentContext(
-    'component_measures',
+    'component_measures?id=foo',
     routes,
     { navigateTo, featureList: [Feature.BranchSupport] },
     { component: mockComponent({ key: 'foo' }), ...componentContext },
index 9976a678389bed8bacf82ab845f4b06f87fba522..e07f41aa4fc17b1bb32a684c358697f53e88d842 100644 (file)
@@ -42,7 +42,7 @@ import { getBranchLikeQuery, isPullRequest, isSameBranchLike } from '../../../he
 import { translate } from '../../../helpers/l10n';
 import { useBranchesQuery } from '../../../queries/branch';
 import { BranchLike } from '../../../types/branch-like';
-import { ComponentQualifier } from '../../../types/component';
+import { ComponentQualifier, isPortfolioLike } from '../../../types/component';
 import { MeasurePageView } from '../../../types/measures';
 import { MetricKey } from '../../../types/metrics';
 import { ComponentMeasure, Dict, MeasureEnhanced, Metric, Period } from '../../../types/types';
@@ -100,25 +100,31 @@ class ComponentMeasuresApp extends React.PureComponent<Props, State> {
       (metrics) => {
         const byKey = keyBy(metrics, 'key');
         this.setState({ metrics: byKey });
-        this.fetchMeasures(byKey);
       },
       () => {},
     );
   }
 
-  componentDidUpdate(prevProps: Props) {
+  componentDidUpdate(prevProps: Props, prevState: State) {
     const prevQuery = parseQuery(prevProps.location.query);
     const query = parseQuery(this.props.location.query);
 
+    const hasSelectedQueryChanged = prevQuery.selected !== query.selected;
+
+    const hasBranchChanged = !isSameBranchLike(prevProps.branchLike, this.props.branchLike);
+
+    const isBranchReady =
+      isPortfolioLike(this.props.component.qualifier) || this.props.branchLike !== undefined;
+
+    const haveMetricsChanged =
+      Object.keys(this.state.metrics).length !== Object.keys(prevState.metrics).length;
+
+    const areMetricsReady = Object.keys(this.state.metrics).length > 0;
+
     if (
-      // If this update is triggered by the branch query resolving, and the metrics query started
-      // in componentDidMount is not done yet, we should not fetch measures just now, as it may
-      // throw a bug in ITs looking for a metric that isn't there yet. In this case the measures
-      // will be fetched once the state updates.
-      Object.keys(this.state.metrics).length > 0 &&
-      (!isSameBranchLike(prevProps.branchLike, this.props.branchLike) ||
-        prevProps.component.key !== this.props.component.key ||
-        prevQuery.selected !== query.selected)
+      areMetricsReady &&
+      isBranchReady &&
+      (haveMetricsChanged || hasBranchChanged || hasSelectedQueryChanged)
     ) {
       this.fetchMeasures(this.state.metrics);
     }