Repository: locustio/locust (language: python)

Issue:
Pressure testing is over, but RPS and Users still have data
### Prerequisites

- [X] I am using [the latest version of Locust](https://github.com/locustio/locust/releases/)
- [X] I am reporting a bug, not asking a question

### Description

As shown in the figure below, when the pressure measurement stops, but RPS and Users still have data, only RT does not.

![image](https://github.com/user-attachments/assets/481a5cbe-27fb-4e0e-b680-46be687dcc39)


### Command line

locust -f gloria_test.py --reset-stats --master --web-login && locust -f gloria_test.py --reset-stats --worker --web-login 

### Locustfile contents

```python3
Nothing to do with content, the simplest will reproduce
```


### Python version

3.11.0

### Locust version

2.31.3

### Operating system

amzn2023.x86_64


Discussion / hints:
I noticed this as well. @andrewbaldwin44 can you have a look? Its not urgent so maybe after next weeks meetings..

Fix patch:
diff --git a/locust/webui/src/hooks/useFetchStats.ts b/locust/webui/src/hooks/useFetchStats.ts
index d0bd9a48a9..80f432c693 100644
--- a/locust/webui/src/hooks/useFetchStats.ts
+++ b/locust/webui/src/hooks/useFetchStats.ts
@@ -17,7 +17,6 @@ export default function useFetchStats() {
   const updateChartMarkers = useAction(uiActions.updateChartMarkers);
   const swarm = useSelector(({ swarm }) => swarm);
   const previousSwarmState = useRef(swarm.state);
-  const hasSetInitStats = useRef(false);
   const [shouldAddMarker, setShouldAddMarker] = useState(false);
 
   const { data: statsData, refetch: refetchStats } = useGetStatsQuery();
@@ -89,17 +88,6 @@ export default function useFetchStats() {
     }
   }, [statsData && statsData.state]);
 
-  useEffect(() => {
-    if (statsData) {
-      if (!hasSetInitStats.current) {
-        // handle setting stats on first load
-        updateStats();
-      }
-
-      hasSetInitStats.current = true;
-    }
-  }, [statsData]);
-
   useInterval(updateStats, STATS_REFETCH_INTERVAL, {
     shouldRunInterval: !!statsData && shouldRunRefetchInterval,
   });


Test patch:
diff --git a/locust/webui/src/hooks/tests/useFetchStats.test.tsx b/locust/webui/src/hooks/tests/useFetchStats.test.tsx
index a0d504c237..9561306be9 100644
--- a/locust/webui/src/hooks/tests/useFetchStats.test.tsx
+++ b/locust/webui/src/hooks/tests/useFetchStats.test.tsx
@@ -1,4 +1,4 @@
-import { act, waitFor } from '@testing-library/react';
+import { act } from '@testing-library/react';
 import { http, HttpResponse } from 'msw';
 import { setupServer } from 'msw/node';
 import { beforeAll, afterEach, afterAll, describe, expect, test, vi } from 'vitest';
@@ -23,27 +23,32 @@ function MockHook() {
 }
 
 describe('useFetchStats', () => {
-  beforeAll(() => server.listen());
+  beforeAll(() => {
+    server.listen();
+    vi.useFakeTimers();
+  });
   afterEach(() => server.resetHandlers());
-  afterAll(() => server.close());
+  afterAll(() => {
+    server.close();
+    vi.useRealTimers();
+  });
 
   test('should fetch request stats and update UI accordingly', async () => {
     const { store } = renderWithProvider(<MockHook />, {
       swarm: { state: SWARM_STATE.RUNNING },
     });
 
-    await waitFor(() => {
-      if (!store.getState().ui.stats.length) {
-        throw new Error();
-      }
+    await act(async () => {
+      await vi.advanceTimersByTimeAsync(2000);
+    });
+    await act(async () => {
+      await vi.advanceTimersByTimeAsync(2000);
     });
 
     expect(store.getState().ui.stats).toEqual(statsResponseTransformed.stats);
   });
 
   test('should add markers to charts between tests', async () => {
-    vi.useFakeTimers();
-
     const testStopTime = new Date().toISOString();
 
     const { store } = renderWithProvider(<MockHook />, {
@@ -62,6 +67,9 @@ describe('useFetchStats', () => {
       store.dispatch(swarmActions.setSwarm({ state: SWARM_STATE.RUNNING }));
     });
 
+    await act(async () => {
+      await vi.advanceTimersByTimeAsync(2000);
+    });
     await act(async () => {
       await vi.advanceTimersByTimeAsync(2000);
     });