This is an automated email from the ASF dual-hosted git repository.

jli pushed a commit to branch fix-missing-dataset-list-test-helper
in repository https://gitbox.apache.org/repos/asf/superset.git

commit e13418fdcb1e5efbedca0ea6511aadedc9a69150
Author: Joe Li <[email protected]>
AuthorDate: Mon Feb 2 19:35:30 2026 -0800

    fix(tests): update DatasetList tests to new fetch-mock API
    
    The fetch-mock library was upgraded and the API changed:
    - fetchMock.reset() → fetchMock.removeRoutes()
    - fetchMock.resetHistory() → fetchMock.clearHistory()
    - fetchMock.restore() → fetchMock.removeRoutes()
    - fetchMock.calls() → fetchMock.callHistory.calls()
    - call[0] → call.url, call[1] → call.options
    - { overwriteRoutes: true } option removed (no longer exists)
    - QueryParamProvider now requires adapter prop
    
    Co-Authored-By: Claude Opus 4.5 <[email protected]>
---
 .../DatasetList/DatasetList.behavior.test.tsx      |  42 +-
 .../DatasetList/DatasetList.integration.test.tsx   |  52 +--
 .../DatasetList/DatasetList.listview.test.tsx      | 446 +++++++++------------
 .../DatasetList/DatasetList.permissions.test.tsx   |  14 +-
 .../src/pages/DatasetList/DatasetList.test.tsx     | 101 ++---
 .../pages/DatasetList/DatasetList.testHelpers.tsx  |  83 ++--
 6 files changed, 318 insertions(+), 420 deletions(-)

diff --git 
a/superset-frontend/src/pages/DatasetList/DatasetList.behavior.test.tsx 
b/superset-frontend/src/pages/DatasetList/DatasetList.behavior.test.tsx
index af73876de11..3f56d7cef5f 100644
--- a/superset-frontend/src/pages/DatasetList/DatasetList.behavior.test.tsx
+++ b/superset-frontend/src/pages/DatasetList/DatasetList.behavior.test.tsx
@@ -62,8 +62,8 @@ afterEach(async () => {
   // Reset browser history state to prevent query params leaking between tests
   window.history.replaceState({}, '', '/');
 
-  fetchMock.resetHistory();
-  fetchMock.restore();
+  fetchMock.clearHistory();
+  fetchMock.removeRoutes();
   jest.restoreAllMocks();
 });
 
@@ -97,7 +97,7 @@ test('typing in search triggers debounced API call with 
search filter', async ()
   const searchInput = within(searchContainer).getByRole('textbox');
 
   // Record initial API calls
-  const initialCallCount = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const initialCallCount = 
fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS).length;
 
   // Type search query and submit with Enter to trigger the debounced fetch
   await userEvent.type(searchInput, 'sales{enter}');
@@ -105,16 +105,16 @@ test('typing in search triggers debounced API call with 
search filter', async ()
   // Wait for debounced API call
   await waitFor(
     () => {
-      const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+      const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
       expect(calls.length).toBeGreaterThan(initialCallCount);
     },
     { timeout: 5000 },
   );
 
   // Verify the latest API call includes search filter in URL
-  const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+  const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
   const latestCall = calls[calls.length - 1];
-  const url = latestCall[0] as string;
+  const url = latestCall.url as string;
 
   // URL should contain filters parameter with search term
   expect(url).toContain('filters');
@@ -140,7 +140,7 @@ test('500 error triggers danger toast with error message', 
async () => {
       status: 500,
       body: { message: 'Internal Server Error' },
     },
-    { overwriteRoutes: true },
+
   );
 
   // Pass toast spy directly via props to bypass withToasts HOC
@@ -162,7 +162,7 @@ test('500 error triggers danger toast with error message', 
async () => {
 
   // Verify toast message contains error keywords
   expect(addDangerToast.mock.calls.length).toBeGreaterThan(0);
-  const toastMessage = String(addDangerToast.mock.calls[0][0]);
+  const toastMessage = String(addDangerToast.mock.calls[0].url);
   expect(
     toastMessage.includes('error') ||
       toastMessage.includes('Error') ||
@@ -177,7 +177,7 @@ test('network timeout triggers danger toast', async () => {
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { throws: new Error('Network timeout') },
-    { overwriteRoutes: true },
+
   );
 
   // Pass toast spy directly via props to bypass withToasts HOC
@@ -199,7 +199,7 @@ test('network timeout triggers danger toast', async () => {
 
   // Verify toast message contains timeout/network keywords
   expect(addDangerToast.mock.calls.length).toBeGreaterThan(0);
-  const toastMessage = String(addDangerToast.mock.calls[0][0]);
+  const toastMessage = String(addDangerToast.mock.calls[0].url);
   expect(
     toastMessage.includes('timeout') ||
       toastMessage.includes('Timeout') ||
@@ -218,7 +218,7 @@ test('clicking delete opens modal with related objects 
count', async () => {
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { result: [datasetToDelete], count: 1 },
-    { overwriteRoutes: true },
+
   );
 
   renderDatasetList(mockAdminUser);
@@ -259,7 +259,7 @@ test('clicking export calls handleResourceExport with 
dataset ID', async () => {
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { result: [datasetToExport], count: 1 },
-    { overwriteRoutes: true },
+
   );
 
   renderDatasetList(mockAdminUser);
@@ -293,13 +293,13 @@ test('clicking duplicate opens modal and submits 
duplicate request', async () =>
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { result: [datasetToDuplicate], count: 1 },
-    { overwriteRoutes: true },
+
   );
 
   fetchMock.post(
     API_ENDPOINTS.DATASET_DUPLICATE,
     { id: 999, table_name: 'Copy of Dataset' },
-    { overwriteRoutes: true },
+
   );
 
   const addSuccessToast = jest.fn();
@@ -314,7 +314,7 @@ test('clicking duplicate opens modal and submits duplicate 
request', async () =>
   });
 
   // Track initial dataset list API calls BEFORE duplicate action
-  const initialDatasetCallCount = fetchMock.calls(
+  const initialDatasetCallCount = fetchMock.callHistory.calls(
     API_ENDPOINTS.DATASETS,
   ).length;
 
@@ -341,11 +341,11 @@ test('clicking duplicate opens modal and submits 
duplicate request', async () =>
 
   // Verify duplicate API was called with correct payload
   await waitFor(() => {
-    const calls = fetchMock.calls(API_ENDPOINTS.DATASET_DUPLICATE);
+    const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASET_DUPLICATE);
     expect(calls.length).toBeGreaterThan(0);
 
     // Verify POST body contains correct dataset info
-    const requestBody = JSON.parse(calls[0][1]?.body as string);
+    const requestBody = JSON.parse(calls[0].options?.body as string);
     expect(requestBody.base_model_id).toBe(datasetToDuplicate.id);
     expect(requestBody.table_name).toBe('Copy of Dataset');
   });
@@ -358,7 +358,7 @@ test('clicking duplicate opens modal and submits duplicate 
request', async () =>
   // Verify refreshData() is called (observable via new dataset list API call)
   await waitFor(
     () => {
-      const datasetCalls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+      const datasetCalls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
       expect(datasetCalls.length).toBeGreaterThan(initialDatasetCallCount);
     },
     { timeout: 3000 },
@@ -382,7 +382,7 @@ test('certified dataset shows badge and tooltip with 
certification details', asy
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { result: [certifiedDataset], count: 1 },
-    { overwriteRoutes: true },
+
   );
 
   renderDatasetList(mockAdminUser);
@@ -423,7 +423,7 @@ test('dataset with warning shows icon and tooltip with 
markdown content', async
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { result: [datasetWithWarning], count: 1 },
-    { overwriteRoutes: true },
+
   );
 
   renderDatasetList(mockAdminUser);
@@ -458,7 +458,7 @@ test('dataset name links to Explore with correct URL and 
accessible label', asyn
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
+
   );
 
   renderDatasetList(mockAdminUser);
diff --git 
a/superset-frontend/src/pages/DatasetList/DatasetList.integration.test.tsx 
b/superset-frontend/src/pages/DatasetList/DatasetList.integration.test.tsx
index 0b228509b2a..80490826077 100644
--- a/superset-frontend/src/pages/DatasetList/DatasetList.integration.test.tsx
+++ b/superset-frontend/src/pages/DatasetList/DatasetList.integration.test.tsx
@@ -62,8 +62,8 @@ afterEach(async () => {
   // Reset browser history state to prevent query params leaking between tests
   window.history.replaceState({}, '', '/');
 
-  fetchMock.resetHistory();
-  fetchMock.restore();
+  fetchMock.clearHistory();
+  fetchMock.removeRoutes();
   jest.restoreAllMocks();
 });
 
@@ -72,11 +72,10 @@ test('ListView provider correctly merges filter + sort + 
pagination state on ref
   // the ListView provider correctly merges them for the API call.
   // Component tests verify individual pieces persist; this verifies they 
COMBINE correctly.
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: mockDatasets, count: mockDatasets.length },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: mockDatasets,
+    count: mockDatasets.length,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -90,30 +89,34 @@ test('ListView provider correctly merges filter + sort + 
pagination state on ref
     name: /Name/i,
   });
 
-  const callsBeforeSort = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const callsBeforeSort = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
   await userEvent.click(nameHeader);
 
   // Wait for sort-triggered refetch to complete before applying filter
   await waitFor(() => {
-    expect(fetchMock.calls(API_ENDPOINTS.DATASETS).length).toBeGreaterThan(
-      callsBeforeSort,
-    );
+    expect(
+      fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS).length,
+    ).toBeGreaterThan(callsBeforeSort);
   });
 
   // 2. Apply a filter using selectOption helper
-  const beforeFilterCallCount = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const beforeFilterCallCount = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
   await selectOption('Virtual', 'Type');
 
   // Wait for filter API call to complete
   await waitFor(() => {
-    const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+    const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
     expect(calls.length).toBeGreaterThan(beforeFilterCallCount);
   });
 
   // 3. Verify the final API call contains ALL three state pieces merged 
correctly
-  const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+  const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
   const latestCall = calls[calls.length - 1];
-  const url = latestCall[0] as string;
+  const url = latestCall.url as string;
 
   // Decode the rison payload using URL parser
   const risonPayload = new URL(url, 'http://localhost').searchParams.get('q');
@@ -147,11 +150,10 @@ test('bulk action orchestration: selection → action → 
cleanup cycle works co
 
   setupBulkDeleteMocks();
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: mockDatasets, count: mockDatasets.length },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: mockDatasets,
+    count: mockDatasets.length,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -213,7 +215,7 @@ test('bulk action orchestration: selection → action → 
cleanup cycle works co
   await userEvent.type(confirmInput, 'DELETE');
 
   // Capture datasets call count before confirming
-  const datasetsCallCountBeforeDelete = fetchMock.calls(
+  const datasetsCallCountBeforeDelete = fetchMock.callHistory.calls(
     API_ENDPOINTS.DATASETS,
   ).length;
 
@@ -224,7 +226,9 @@ test('bulk action orchestration: selection → action → 
cleanup cycle works co
 
   // 3. Wait for bulk delete API call to be made
   await waitFor(() => {
-    const deleteCalls = fetchMock.calls(API_ENDPOINTS.DATASET_BULK_DELETE);
+    const deleteCalls = fetchMock.callHistory.calls(
+      API_ENDPOINTS.DATASET_BULK_DELETE,
+    );
     expect(deleteCalls.length).toBeGreaterThan(0);
   });
 
@@ -235,7 +239,9 @@ test('bulk action orchestration: selection → action → 
cleanup cycle works co
 
   // Wait for datasets refetch after delete
   await waitFor(() => {
-    const datasetsCallCount = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+    const datasetsCallCount = fetchMock.callHistory.calls(
+      API_ENDPOINTS.DATASETS,
+    ).length;
     expect(datasetsCallCount).toBeGreaterThan(datasetsCallCountBeforeDelete);
   });
 
diff --git 
a/superset-frontend/src/pages/DatasetList/DatasetList.listview.test.tsx 
b/superset-frontend/src/pages/DatasetList/DatasetList.listview.test.tsx
index b43f78dc9c4..84573b873ee 100644
--- a/superset-frontend/src/pages/DatasetList/DatasetList.listview.test.tsx
+++ b/superset-frontend/src/pages/DatasetList/DatasetList.listview.test.tsx
@@ -112,11 +112,7 @@ const setupErrorTestScenario = ({
   });
 
   // Configure fetchMock to return single dataset
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
   // Render component with toast mocks
   renderDatasetList(mockAdminUser, {
@@ -143,8 +139,8 @@ afterEach(async () => {
   // QueryParamProvider reads from window.history, which persists across 
renders
   window.history.replaceState({}, '', '/');
 
-  fetchMock.resetHistory();
-  fetchMock.restore();
+  fetchMock.clearHistory();
+  fetchMock.removeRoutes();
   jest.restoreAllMocks();
 });
 
@@ -199,11 +195,7 @@ test('renders all required column headers', async () => {
 test('displays dataset name in Name column', async () => {
   const dataset = mockDatasets[0];
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
   renderDatasetList(mockAdminUser);
 
@@ -216,11 +208,10 @@ test('displays dataset type as Physical or Virtual', 
async () => {
   const physicalDataset = mockDatasets[0]; // kind: 'physical'
   const virtualDataset = mockDatasets[1]; // kind: 'virtual'
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [physicalDataset, virtualDataset], count: 2 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [physicalDataset, virtualDataset],
+    count: 2,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -234,11 +225,7 @@ test('displays dataset type as Physical or Virtual', async 
() => {
 test('displays database name in Database column', async () => {
   const dataset = mockDatasets[0];
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
   renderDatasetList(mockAdminUser);
 
@@ -252,11 +239,7 @@ test('displays database name in Database column', async () 
=> {
 test('displays schema name in Schema column', async () => {
   const dataset = mockDatasets[0];
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
   renderDatasetList(mockAdminUser);
 
@@ -268,11 +251,7 @@ test('displays schema name in Schema column', async () => {
 test('displays last modified date in humanized format', async () => {
   const dataset = mockDatasets[0];
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
   renderDatasetList(mockAdminUser);
 
@@ -296,21 +275,23 @@ test('sorting by Name column updates API call with sort 
parameter', async () =>
   });
 
   // Record initial calls
-  const initialCalls = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const initialCalls = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
 
   // Click Name header to sort
   await userEvent.click(nameHeader);
 
   // Wait for new API call
   await waitFor(() => {
-    const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+    const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
     expect(calls.length).toBeGreaterThan(initialCalls);
   });
 
   // Verify latest call includes sort parameter
-  const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+  const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
   const latestCall = calls[calls.length - 1];
-  const url = latestCall[0] as string;
+  const url = latestCall.url as string;
 
   // URL should contain order_column for sorting
   expect(url).toMatch(/order_column|sort/);
@@ -328,17 +309,19 @@ test('sorting by Database column updates sort parameter', 
async () => {
     name: /Database/i,
   });
 
-  const initialCalls = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const initialCalls = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
 
   await userEvent.click(databaseHeader);
 
   await waitFor(() => {
-    const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+    const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
     expect(calls.length).toBeGreaterThan(initialCalls);
   });
 
-  const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
-  const url = calls[calls.length - 1][0] as string;
+  const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
+  const url = calls[calls.length - 1].url as string;
   expect(url).toMatch(/order_column|sort/);
 });
 
@@ -354,28 +337,26 @@ test('sorting by Last modified column updates sort 
parameter', async () => {
     name: /Last modified/i,
   });
 
-  const initialCalls = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const initialCalls = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
 
   await userEvent.click(modifiedHeader);
 
   await waitFor(() => {
-    const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+    const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
     expect(calls.length).toBeGreaterThan(initialCalls);
   });
 
-  const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
-  const url = calls[calls.length - 1][0] as string;
+  const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
+  const url = calls[calls.length - 1].url as string;
   expect(url).toMatch(/order_column|sort/);
 });
 
 test('export button triggers handleResourceExport with dataset ID', async () 
=> {
   const dataset = mockDatasets[0];
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
   renderDatasetList(mockAdminUser);
 
@@ -403,11 +384,7 @@ test('delete button opens modal with dataset details', 
async () => {
 
   setupDeleteMocks(dataset.id);
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
   renderDatasetList(mockAdminUser);
 
@@ -429,11 +406,10 @@ test('delete action successfully deletes dataset and 
refreshes list', async () =
   const datasetToDelete = mockDatasets[0];
   setupDeleteMocks(datasetToDelete.id);
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [datasetToDelete], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [datasetToDelete],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser, {
     addSuccessToast: mockAddSuccessToast,
@@ -455,7 +431,9 @@ test('delete action successfully deletes dataset and 
refreshes list', async () =
   await userEvent.type(confirmInput, 'DELETE');
 
   // Track API calls before confirm
-  const callsBefore = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const callsBefore = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
 
   // Click confirm - find the danger button (last delete button in modal)
   const confirmButton = within(modal)
@@ -465,11 +443,11 @@ test('delete action successfully deletes dataset and 
refreshes list', async () =
 
   // Wait for delete API call
   await waitFor(() => {
-    const deleteCalls = fetchMock.calls(
+    const deleteCalls = fetchMock.callHistory.calls(
       `glob:*/api/v1/dataset/${datasetToDelete.id}`,
     );
     const hasDelete = deleteCalls.some(
-      call => (call[1] as RequestInit)?.method === 'DELETE',
+      call => (call.options as RequestInit)?.method === 'DELETE',
     );
     expect(hasDelete).toBe(true);
   });
@@ -482,9 +460,9 @@ test('delete action successfully deletes dataset and 
refreshes list', async () =
 
   // List refreshes
   await waitFor(() => {
-    expect(fetchMock.calls(API_ENDPOINTS.DATASETS).length).toBeGreaterThan(
-      callsBefore,
-    );
+    expect(
+      fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS).length,
+    ).toBeGreaterThan(callsBefore);
   });
 });
 
@@ -492,11 +470,7 @@ test('delete action cancel closes modal without deleting', 
async () => {
   const dataset = mockDatasets[0];
   setupDeleteMocks(dataset.id);
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
   renderDatasetList(mockAdminUser);
 
@@ -520,9 +494,11 @@ test('delete action cancel closes modal without deleting', 
async () => {
   });
 
   // No delete API call made (only related_objects GET was called)
-  const deleteCalls = fetchMock.calls(`glob:*/api/v1/dataset/${dataset.id}`);
+  const deleteCalls = fetchMock.callHistory.calls(
+    `glob:*/api/v1/dataset/${dataset.id}`,
+  );
   const hasDeleteMethod = deleteCalls.some(
-    call => (call[1] as RequestInit)?.method === 'DELETE',
+    call => (call.options as RequestInit)?.method === 'DELETE',
   );
   expect(hasDeleteMethod).toBe(false);
 
@@ -534,11 +510,7 @@ test('duplicate action successfully duplicates virtual 
dataset', async () => {
   const virtualDataset = mockDatasets[1]; // Virtual dataset (kind: 'virtual')
   setupDuplicateMocks();
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [virtualDataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [virtualDataset], count: 1 
});
 
   renderDatasetList(mockAdminUser, {
     addSuccessToast: mockAddSuccessToast,
@@ -560,7 +532,9 @@ test('duplicate action successfully duplicates virtual 
dataset', async () => {
   await userEvent.type(input, 'Copy of Analytics');
 
   // Track API calls before submit
-  const callsBefore = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const callsBefore = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
 
   // Submit
   const submitButton = within(modal).getByRole('button', {
@@ -570,7 +544,9 @@ test('duplicate action successfully duplicates virtual 
dataset', async () => {
 
   // Wait for duplicate API call and modal closes
   await waitFor(() => {
-    const dupCalls = fetchMock.calls(API_ENDPOINTS.DATASET_DUPLICATE);
+    const dupCalls = fetchMock.callHistory.calls(
+      API_ENDPOINTS.DATASET_DUPLICATE,
+    );
     expect(dupCalls.length).toBeGreaterThan(0);
     // Modal closes (duplicate success doesn't show toast, just closes modal)
     expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
@@ -578,9 +554,9 @@ test('duplicate action successfully duplicates virtual 
dataset', async () => {
 
   // List refreshes
   await waitFor(() => {
-    expect(fetchMock.calls(API_ENDPOINTS.DATASETS).length).toBeGreaterThan(
-      callsBefore,
-    );
+    expect(
+      fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS).length,
+    ).toBeGreaterThan(callsBefore);
   });
 });
 
@@ -588,11 +564,10 @@ test('duplicate button visible only for virtual 
datasets', async () => {
   const physicalDataset = mockDatasets[0]; // kind: 'physical'
   const virtualDataset = mockDatasets[1]; // kind: 'virtual'
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [physicalDataset, virtualDataset], count: 2 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [physicalDataset, virtualDataset],
+    count: 2,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -648,11 +623,10 @@ test('bulk select enables checkboxes', async () => {
 }, 30000);
 
 test('selecting all datasets shows correct count in toolbar', async () => {
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: mockDatasets, count: mockDatasets.length },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: mockDatasets,
+    count: mockDatasets.length,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -688,11 +662,10 @@ test('selecting all datasets shows correct count in 
toolbar', async () => {
 }, 30000);
 
 test('bulk export triggers export with selected IDs', async () => {
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [mockDatasets[0]], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [mockDatasets[0]],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -731,11 +704,10 @@ test('bulk export triggers export with selected IDs', 
async () => {
 test('bulk delete opens confirmation modal', async () => {
   setupBulkDeleteMocks();
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [mockDatasets[0]], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [mockDatasets[0]],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -838,11 +810,10 @@ test('certified badge appears for certified datasets', 
async () => {
     }),
   };
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [certifiedDataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [certifiedDataset],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -869,11 +840,10 @@ test('warning icon appears for datasets with warnings', 
async () => {
     }),
   };
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [datasetWithWarning], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [datasetWithWarning],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -898,11 +868,10 @@ test('info tooltip appears for datasets with 
descriptions', async () => {
     description: 'Sales data from Q4 2024',
   };
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [datasetWithDescription], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [datasetWithDescription],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -924,11 +893,7 @@ test('info tooltip appears for datasets with 
descriptions', async () => {
 test('dataset name links to Explore page', async () => {
   const dataset = mockDatasets[0];
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
   renderDatasetList(mockAdminUser);
 
@@ -948,11 +913,10 @@ test('dataset name links to Explore page', async () => {
 test('physical dataset shows delete, export, and edit actions (no duplicate)', 
async () => {
   const physicalDataset = mockDatasets[0]; // kind: 'physical'
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [physicalDataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [physicalDataset],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -980,11 +944,7 @@ test('physical dataset shows delete, export, and edit 
actions (no duplicate)', a
 test('virtual dataset shows delete, export, edit, and duplicate actions', 
async () => {
   const virtualDataset = mockDatasets[1]; // kind: 'virtual'
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [virtualDataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [virtualDataset], count: 1 
});
 
   renderDatasetList(mockAdminUser);
 
@@ -1013,11 +973,7 @@ test('edit action is enabled for dataset owner', async () 
=> {
     owners: [{ id: mockAdminUser.userId, username: 'admin' }],
   };
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
   renderDatasetList(mockAdminUser);
 
@@ -1040,11 +996,7 @@ test('edit action is disabled for non-owner', async () => 
{
     owners: [{ id: 999, username: 'other_user' }], // Different user
   };
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
   // Use a non-admin user to test ownership check
   const regularUser = {
@@ -1073,11 +1025,7 @@ test('all action buttons are clickable and enabled for 
admin user', async () =>
     owners: [{ id: mockAdminUser.userId, username: 'admin' }],
   };
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [virtualDataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [virtualDataset], count: 1 
});
 
   renderDatasetList(mockAdminUser);
 
@@ -1112,11 +1060,10 @@ test('all action buttons are clickable and enabled for 
admin user', async () =>
 });
 
 test('displays error when initial dataset fetch fails with 500', async () => {
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { status: 500, body: { message: 'Internal Server Error' } },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    status: 500,
+    body: { message: 'Internal Server Error' },
+  });
 
   renderDatasetList(mockAdminUser, {
     addDangerToast: mockAddDangerToast,
@@ -1134,11 +1081,10 @@ test('displays error when initial dataset fetch fails 
with 500', async () => {
 });
 
 test('displays error when initial dataset fetch fails with 403 permission 
denied', async () => {
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { status: 403, body: { message: 'Access Denied' } },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    status: 403,
+    body: { message: 'Access Denied' },
+  });
 
   renderDatasetList(mockAdminUser, {
     addDangerToast: mockAddDangerToast,
@@ -1150,7 +1096,7 @@ test('displays error when initial dataset fetch fails 
with 403 permission denied
   });
 
   // Verify toast message contains the 403-specific "Access Denied" text
-  const toastMessage = String(mockAddDangerToast.mock.calls[0][0]);
+  const toastMessage = String(mockAddDangerToast.mock.calls[0].url);
   expect(toastMessage).toContain('Access Denied');
 
   // No dataset names from mockDatasets should appear in the document
@@ -1402,20 +1348,22 @@ test('sort order persists after deleting a dataset', 
async () => {
   });
 
   // Record initial API calls count
-  const initialCalls = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const initialCalls = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
 
   // Click Name header to sort
   await userEvent.click(nameHeader);
 
   // Wait for new API call with sort parameter
   await waitFor(() => {
-    const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+    const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
     expect(calls.length).toBeGreaterThan(initialCalls);
   });
 
   // Record the sort parameter from the API call after sorting
-  const callsAfterSort = fetchMock.calls(API_ENDPOINTS.DATASETS);
-  const sortedUrl = callsAfterSort[callsAfterSort.length - 1][0] as string;
+  const callsAfterSort = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
+  const sortedUrl = callsAfterSort[callsAfterSort.length - 1].url as string;
   expect(sortedUrl).toMatch(/order_column|sort/);
 
   // Delete a dataset - get delete button from first row only
@@ -1433,7 +1381,9 @@ test('sort order persists after deleting a dataset', 
async () => {
   await userEvent.type(confirmInput, 'DELETE');
 
   // Record call count before delete to track refetch
-  const callsBeforeDelete = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const callsBeforeDelete = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
 
   const confirmButton = within(modal)
     .getAllByRole('button', { name: /^delete$/i })
@@ -1452,7 +1402,9 @@ test('sort order persists after deleting a dataset', 
async () => {
 
   // Wait for list refetch to complete (prevents async cleanup error)
   await waitFor(() => {
-    const currentCalls = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+    const currentCalls = fetchMock.callHistory.calls(
+      API_ENDPOINTS.DATASETS,
+    ).length;
     expect(currentCalls).toBeGreaterThan(callsBeforeDelete);
   });
 
@@ -1476,11 +1428,10 @@ test('sort order persists after deleting a dataset', 
async () => {
 // test. Component tests here focus on individual behaviors.
 
 test('bulk selection clears when filter changes', async () => {
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: mockDatasets, count: mockDatasets.length },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: mockDatasets,
+    count: mockDatasets.length,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -1528,7 +1479,9 @@ test('bulk selection clears when filter changes', async 
() => {
   });
 
   // Record API call count before filter
-  const beforeFilterCallCount = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const beforeFilterCallCount = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
 
   // Wait for filter combobox to be ready before applying filter
   await screen.findByRole('combobox', { name: 'Type' });
@@ -1538,14 +1491,14 @@ test('bulk selection clears when filter changes', async 
() => {
 
   // Wait for filter API call to complete
   await waitFor(() => {
-    const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+    const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
     expect(calls.length).toBeGreaterThan(beforeFilterCallCount);
   });
 
   // Verify filter was applied by decoding URL payload
-  const urlAfterFilter = fetchMock
+  const urlAfterFilter = fetchMock.callHistory
     .calls(API_ENDPOINTS.DATASETS)
-    .at(-1)?.[0] as string;
+    .at(-1)?.url as string;
   const risonAfterFilter = new URL(
     urlAfterFilter,
     'http://localhost',
@@ -1578,19 +1531,22 @@ test('type filter API call includes correct filter 
parameter', async () => {
   await screen.findByRole('combobox', { name: 'Type' });
 
   // Snapshot call count before filter
-  const callsBeforeFilter = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const callsBeforeFilter = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
 
   // Apply Type filter
   await selectOption('Virtual', 'Type');
 
   // Wait for filter API call to complete
   await waitFor(() => {
-    const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+    const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
     expect(calls.length).toBeGreaterThan(callsBeforeFilter);
   });
 
   // Verify the latest API call includes the Type filter
-  const url = fetchMock.calls(API_ENDPOINTS.DATASETS).at(-1)?.[0] as string;
+  const url = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS).at(-1)
+    ?.url as string;
   expect(url).toContain('filters');
 
   // searchParams.get() already URL-decodes, so pass directly to rison.decode
@@ -1622,21 +1578,23 @@ test('type filter persists after duplicating a 
dataset', async () => {
   await screen.findByRole('combobox', { name: 'Type' });
 
   // Snapshot call count before filter
-  const callsBeforeFilter = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const callsBeforeFilter = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
 
   // Apply Type filter
   await selectOption('Virtual', 'Type');
 
   // Wait for filter API call to complete
   await waitFor(() => {
-    const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+    const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
     expect(calls.length).toBeGreaterThan(callsBeforeFilter);
   });
 
   // Verify filter is present by checking the latest API call
-  const urlAfterFilter = fetchMock
+  const urlAfterFilter = fetchMock.callHistory
     .calls(API_ENDPOINTS.DATASETS)
-    .at(-1)?.[0] as string;
+    .at(-1)?.url as string;
   const risonAfterFilter = new URL(
     urlAfterFilter,
     'http://localhost',
@@ -1654,7 +1612,7 @@ test('type filter persists after duplicating a dataset', 
async () => {
   );
 
   // Capture datasets API call count BEFORE any duplicate operations
-  const datasetsCallCountBeforeDuplicate = fetchMock.calls(
+  const datasetsCallCountBeforeDuplicate = fetchMock.callHistory.calls(
     API_ENDPOINTS.DATASETS,
   ).length;
 
@@ -1682,20 +1640,24 @@ test('type filter persists after duplicating a 
dataset', async () => {
 
   // Wait for duplicate API call to be made
   await waitFor(() => {
-    const duplicateCalls = fetchMock.calls(API_ENDPOINTS.DATASET_DUPLICATE);
+    const duplicateCalls = fetchMock.callHistory.calls(
+      API_ENDPOINTS.DATASET_DUPLICATE,
+    );
     expect(duplicateCalls.length).toBeGreaterThan(0);
   });
 
   // Wait for datasets refetch to occur (proves duplicate triggered a refresh)
   await waitFor(() => {
-    const datasetsCallCount = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+    const datasetsCallCount = fetchMock.callHistory.calls(
+      API_ENDPOINTS.DATASETS,
+    ).length;
     
expect(datasetsCallCount).toBeGreaterThan(datasetsCallCountBeforeDuplicate);
   });
 
   // Verify Type filter persisted in the NEW datasets API call after 
duplication
-  const urlAfterDuplicate = fetchMock
+  const urlAfterDuplicate = fetchMock.callHistory
     .calls(API_ENDPOINTS.DATASETS)
-    .at(-1)?.[0] as string;
+    .at(-1)?.url as string;
   const risonAfterDuplicate = new URL(
     urlAfterDuplicate,
     'http://localhost',
@@ -1729,11 +1691,7 @@ test('edit action shows error toast when dataset fetch 
fails', async () => {
     ],
   };
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [ownedDataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [ownedDataset], count: 1 });
 
   // Mock SupersetClient.get to fail for the specific dataset endpoint
   jest.spyOn(SupersetClient, 'get').mockImplementation(async request => {
@@ -1776,11 +1734,10 @@ test('bulk export error shows toast and clears loading 
state', async () => {
   // Mock handleResourceExport to throw an error
   mockHandleResourceExport.mockRejectedValueOnce(new Error('Export failed'));
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [mockDatasets[0]], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [mockDatasets[0]],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser, {
     addDangerToast: mockAddDangerToast,
@@ -1836,17 +1793,15 @@ test('bulk export error shows toast and clears loading 
state', async () => {
 
 test('bulk delete error shows toast without refreshing list', async () => {
   // Mock bulk delete to fail
-  fetchMock.delete(
-    API_ENDPOINTS.DATASET_BULK_DELETE,
-    { status: 500, body: { message: 'Bulk delete failed' } },
-    { overwriteRoutes: true },
-  );
+  fetchMock.delete(API_ENDPOINTS.DATASET_BULK_DELETE, {
+    status: 500,
+    body: { message: 'Bulk delete failed' },
+  });
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [mockDatasets[0]], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [mockDatasets[0]],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser, {
     addDangerToast: mockAddDangerToast,
@@ -1919,11 +1874,10 @@ test('bulk select shows "N Selected (Virtual)" for 
virtual-only selection', asyn
   // Use only virtual datasets
   const virtualDatasets = mockDatasets.filter(d => d.kind === 'virtual');
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: virtualDatasets, count: virtualDatasets.length },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: virtualDatasets,
+    count: virtualDatasets.length,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -1966,11 +1920,10 @@ test('bulk select shows "N Selected (Physical)" for 
physical-only selection', as
   // Use only physical datasets
   const physicalDatasets = mockDatasets.filter(d => d.kind === 'physical');
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: physicalDatasets, count: physicalDatasets.length },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: physicalDatasets,
+    count: physicalDatasets.length,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -2017,11 +1970,10 @@ test('bulk select shows mixed count for virtual and 
physical selection', async (
     mockDatasets.find(d => d.kind === 'virtual')!,
   ];
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: mixedDatasets, count: mixedDatasets.length },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: mixedDatasets,
+    count: mixedDatasets.length,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -2081,20 +2033,12 @@ test('delete modal shows affected dashboards with 
overflow for >10 items', async
     title: `Dashboard ${i + 1}`,
   }));
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
-  fetchMock.get(
-    `glob:*/api/v1/dataset/${dataset.id}/related_objects*`,
-    {
-      charts: { count: 0, result: [] },
-      dashboards: { count: 15, result: manyDashboards },
-    },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(`glob:*/api/v1/dataset/${dataset.id}/related_objects*`, {
+    charts: { count: 0, result: [] },
+    dashboards: { count: 15, result: manyDashboards },
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -2126,20 +2070,12 @@ test('delete modal shows affected dashboards with 
overflow for >10 items', async
 test('delete modal hides affected dashboards section when count is zero', 
async () => {
   const dataset = mockDatasets[0];
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
-  fetchMock.get(
-    `glob:*/api/v1/dataset/${dataset.id}/related_objects*`,
-    {
-      charts: { count: 2, result: [{ id: 1, slice_name: 'Chart 1' }] },
-      dashboards: { count: 0, result: [] },
-    },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(`glob:*/api/v1/dataset/${dataset.id}/related_objects*`, {
+    charts: { count: 2, result: [{ id: 1, slice_name: 'Chart 1' }] },
+    dashboards: { count: 0, result: [] },
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -2172,20 +2108,12 @@ test('delete modal shows affected charts with overflow 
for >10 items', async ()
     slice_name: `Chart ${i + 1}`,
   }));
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
-  fetchMock.get(
-    `glob:*/api/v1/dataset/${dataset.id}/related_objects*`,
-    {
-      charts: { count: 12, result: manyCharts },
-      dashboards: { count: 0, result: [] },
-    },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(`glob:*/api/v1/dataset/${dataset.id}/related_objects*`, {
+    charts: { count: 12, result: manyCharts },
+    dashboards: { count: 0, result: [] },
+  });
 
   renderDatasetList(mockAdminUser);
 
diff --git 
a/superset-frontend/src/pages/DatasetList/DatasetList.permissions.test.tsx 
b/superset-frontend/src/pages/DatasetList/DatasetList.permissions.test.tsx
index a997ff9a551..331e1c4f9d8 100644
--- a/superset-frontend/src/pages/DatasetList/DatasetList.permissions.test.tsx
+++ b/superset-frontend/src/pages/DatasetList/DatasetList.permissions.test.tsx
@@ -51,8 +51,8 @@ afterEach(async () => {
   // Reset browser history to prevent query param leakage
   window.history.replaceState({}, '', '/');
 
-  fetchMock.resetHistory();
-  fetchMock.restore();
+  fetchMock.clearHistory();
+  fetchMock.removeRoutes();
   jest.restoreAllMocks();
 });
 
@@ -240,7 +240,7 @@ test('action buttons respect user permissions', async () => 
{
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
+
   );
 
   renderDatasetList(mockAdminUser);
@@ -270,7 +270,7 @@ test('read-only user sees no delete or duplicate buttons in 
row', async () => {
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
+
   );
 
   renderDatasetList(mockReadOnlyUser);
@@ -309,7 +309,7 @@ test('write user sees edit, delete, and export actions', 
async () => {
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
+
   );
 
   renderDatasetList(mockWriteUser);
@@ -348,7 +348,7 @@ test('export-only user has no Actions column (no 
write/duplicate permissions)',
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
+
   );
 
   renderDatasetList(mockExportOnlyUser);
@@ -385,7 +385,7 @@ test('user with can_duplicate sees duplicate button only 
for virtual datasets',
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { result: [physicalDataset, virtualDataset], count: 2 },
-    { overwriteRoutes: true },
+
   );
 
   renderDatasetList(mockAdminUser);
diff --git a/superset-frontend/src/pages/DatasetList/DatasetList.test.tsx 
b/superset-frontend/src/pages/DatasetList/DatasetList.test.tsx
index 51ad4cbab7a..6e9808762a1 100644
--- a/superset-frontend/src/pages/DatasetList/DatasetList.test.tsx
+++ b/superset-frontend/src/pages/DatasetList/DatasetList.test.tsx
@@ -53,8 +53,8 @@ afterEach(async () => {
   // Reset browser history state to prevent query params leaking between tests
   window.history.replaceState({}, '', '/');
 
-  fetchMock.resetHistory();
-  fetchMock.restore();
+  fetchMock.clearHistory();
+  fetchMock.removeRoutes();
   jest.restoreAllMocks();
 });
 
@@ -74,7 +74,6 @@ test('shows loading state during initial data fetch', () => {
     new Promise(resolve =>
       setTimeout(() => resolve({ result: [], count: 0 }), 10000),
     ),
-    { overwriteRoutes: true },
   );
 
   renderDatasetList(mockAdminUser);
@@ -93,7 +92,6 @@ test('maintains component structure during loading', () => {
     new Promise(resolve =>
       setTimeout(() => resolve({ result: [], count: 0 }), 10000),
     ),
-    { overwriteRoutes: true },
   );
 
   renderDatasetList(mockAdminUser);
@@ -215,11 +213,10 @@ test('handles datasets with missing fields and renders 
gracefully', async () =>
     sql: null,
   };
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [datasetWithMissingFields], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [datasetWithMissingFields],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -242,11 +239,7 @@ test('handles datasets with missing fields and renders 
gracefully', async () =>
 });
 
 test('handles empty results (shows empty state)', async () => {
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [], count: 0 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [], count: 0 });
 
   renderDatasetList(mockAdminUser);
 
@@ -258,7 +251,7 @@ test('makes correct initial API call on load', async () => {
   renderDatasetList(mockAdminUser);
 
   await waitFor(() => {
-    const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+    const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
     expect(calls.length).toBeGreaterThan(0);
   });
 });
@@ -267,9 +260,9 @@ test('API call includes correct page size', async () => {
   renderDatasetList(mockAdminUser);
 
   await waitFor(() => {
-    const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+    const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
     expect(calls.length).toBeGreaterThan(0);
-    const url = calls[0][0] as string;
+    const url = calls[0].url as string;
     expect(url).toContain('page_size');
   });
 });
@@ -281,7 +274,9 @@ test('typing in name filter updates input value and 
triggers API with decoded se
   const searchInput = within(searchContainer).getByRole('textbox');
 
   // Record initial API calls
-  const initialCallCount = fetchMock.calls(API_ENDPOINTS.DATASETS).length;
+  const initialCallCount = fetchMock.callHistory.calls(
+    API_ENDPOINTS.DATASETS,
+  ).length;
 
   // Type in search box and press Enter to trigger search
   await userEvent.type(searchInput, 'sales{enter}');
@@ -294,11 +289,11 @@ test('typing in name filter updates input value and 
triggers API with decoded se
   // Wait for API call after Enter key press
   await waitFor(
     () => {
-      const calls = fetchMock.calls(API_ENDPOINTS.DATASETS);
+      const calls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
       expect(calls.length).toBeGreaterThan(initialCallCount);
 
       // Get latest API call
-      const url = calls[calls.length - 1][0] as string;
+      const url = calls[calls.length - 1].url as string;
 
       // Verify URL contains search filter
       expect(url).toContain('filters');
@@ -351,9 +346,7 @@ test('handles 500 error on initial load without crashing', 
async () => {
   fetchMock.get(
     API_ENDPOINTS.DATASETS,
     { throws: new Error('Internal Server Error') },
-    {
-      overwriteRoutes: true,
-    },
+    {},
   );
 
   renderDatasetList(mockAdminUser, {
@@ -369,9 +362,7 @@ test('handles 500 error on initial load without crashing', 
async () => {
 test('handles 403 error on _info endpoint and disables create actions', async 
() => {
   const addDangerToast = jest.fn();
 
-  fetchMock.get(API_ENDPOINTS.DATASETS_INFO, mockApiError403, {
-    overwriteRoutes: true,
-  });
+  fetchMock.get(API_ENDPOINTS.DATASETS_INFO, mockApiError403, {});
 
   renderDatasetList(mockAdminUser, {
     addDangerToast,
@@ -391,11 +382,9 @@ test('handles 403 error on _info endpoint and disables 
create actions', async ()
 });
 
 test('handles network timeout without crashing', async () => {
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { throws: new Error('Network timeout') },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    throws: new Error('Network timeout'),
+  });
 
   renderDatasetList(mockAdminUser, {
     addDangerToast: jest.fn(),
@@ -412,7 +401,7 @@ test('component requires explicit mocks for all API 
endpoints', async () => {
   setupMocks();
 
   // Clear call history to start fresh
-  fetchMock.resetHistory();
+  fetchMock.clearHistory();
 
   // Render component with standard setup
   renderDatasetList(mockAdminUser);
@@ -421,15 +410,15 @@ test('component requires explicit mocks for all API 
endpoints', async () => {
   await waitForDatasetsPageReady();
 
   // Verify that critical endpoints were called and had mocks available
-  const newDatasetsCalls = fetchMock.calls(API_ENDPOINTS.DATASETS);
-  const newInfoCalls = fetchMock.calls(API_ENDPOINTS.DATASETS_INFO);
+  const newDatasetsCalls = fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS);
+  const newInfoCalls = 
fetchMock.callHistory.calls(API_ENDPOINTS.DATASETS_INFO);
 
   // These should have been called during render
   expect(newDatasetsCalls.length).toBeGreaterThan(0);
   expect(newInfoCalls.length).toBeGreaterThan(0);
 
   // Verify no unmatched calls (all endpoints were mocked)
-  const unmatchedCalls = fetchMock.calls(false); // false = unmatched only
+  const unmatchedCalls = fetchMock.callHistory.calls(false); // false = 
unmatched only
   expect(unmatchedCalls.length).toBe(0);
 });
 
@@ -453,11 +442,10 @@ test('renders datasets with certification data', async () 
=> {
     }),
   };
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [certifiedDataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [certifiedDataset],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -481,11 +469,10 @@ test('displays datasets with warning_markdown', async () 
=> {
     }),
   };
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [datasetWithWarning], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [datasetWithWarning],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -503,11 +490,10 @@ test('displays datasets with warning_markdown', async () 
=> {
 test('displays dataset with multiple owners', async () => {
   const datasetWithOwners = mockDatasets[1]; // Has 2 owners: Jane Smith, Bob 
Jones
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [datasetWithOwners], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [datasetWithOwners],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -525,11 +511,10 @@ test('displays dataset with multiple owners', async () => 
{
 test('displays ModifiedInfo with humanized date', async () => {
   const datasetWithModified = mockDatasets[0]; // changed_by_name: 'John Doe', 
changed_on: '1 day ago'
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [datasetWithModified], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, {
+    result: [datasetWithModified],
+    count: 1,
+  });
 
   renderDatasetList(mockAdminUser);
 
@@ -548,11 +533,7 @@ test('displays ModifiedInfo with humanized date', async () 
=> {
 test('dataset name links to Explore with correct explore_url', async () => {
   const dataset = mockDatasets[0]; // explore_url: 
'/explore/?datasource=1__table'
 
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS,
-    { result: [dataset], count: 1 },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(API_ENDPOINTS.DATASETS, { result: [dataset], count: 1 });
 
   renderDatasetList(mockAdminUser);
 
diff --git 
a/superset-frontend/src/pages/DatasetList/DatasetList.testHelpers.tsx 
b/superset-frontend/src/pages/DatasetList/DatasetList.testHelpers.tsx
index 844ad8f9163..6b160eac5eb 100644
--- a/superset-frontend/src/pages/DatasetList/DatasetList.testHelpers.tsx
+++ b/superset-frontend/src/pages/DatasetList/DatasetList.testHelpers.tsx
@@ -23,6 +23,7 @@ import { Provider } from 'react-redux';
 import { MemoryRouter } from 'react-router-dom';
 import { configureStore } from '@reduxjs/toolkit';
 import { QueryParamProvider } from 'use-query-params';
+import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5';
 import DatasetList from 'src/pages/DatasetList';
 import handleResourceExport from 'src/utils/export';
 
@@ -331,11 +332,8 @@ export const API_ENDPOINTS = {
 
 // Setup API permissions mock (for permission-based testing)
 export const setupApiPermissions = (permissions: string[]) => {
-  fetchMock.get(
-    API_ENDPOINTS.DATASETS_INFO,
-    { permissions },
-    { overwriteRoutes: true },
-  );
+  fetchMock.removeRoute(API_ENDPOINTS.DATASETS_INFO);
+  fetchMock.get(API_ENDPOINTS.DATASETS_INFO, { permissions });
 };
 
 // Store utilities
@@ -384,7 +382,7 @@ export const renderDatasetList = (
   return render(
     <Provider store={store}>
       <MemoryRouter>
-        <QueryParamProvider>
+        <QueryParamProvider adapter={ReactRouter5Adapter}>
           <DatasetList user={user} {...props} />
         </QueryParamProvider>
       </MemoryRouter>
@@ -402,36 +400,27 @@ export const waitForDatasetsPageReady = async () => {
 
 // Helper functions for specific operations
 export const setupDeleteMocks = (datasetId: number) => {
-  fetchMock.get(
-    `glob:*/api/v1/dataset/${datasetId}/related_objects*`,
-    {
-      charts: mockRelatedCharts,
-      dashboards: mockRelatedDashboards,
-    },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(`glob:*/api/v1/dataset/${datasetId}/related_objects*`, {
+    charts: mockRelatedCharts,
+    dashboards: mockRelatedDashboards,
+  });
 
-  fetchMock.delete(
-    `glob:*/api/v1/dataset/${datasetId}`,
-    { message: 'Dataset deleted successfully' },
-    { overwriteRoutes: true },
-  );
+  fetchMock.delete(`glob:*/api/v1/dataset/${datasetId}`, {
+    message: 'Dataset deleted successfully',
+  });
 };
 
 export const setupDuplicateMocks = () => {
-  fetchMock.post(
-    API_ENDPOINTS.DATASET_DUPLICATE,
-    { id: 999, table_name: 'Copy of Dataset' },
-    { overwriteRoutes: true },
-  );
+  fetchMock.post(API_ENDPOINTS.DATASET_DUPLICATE, {
+    id: 999,
+    table_name: 'Copy of Dataset',
+  });
 };
 
 export const setupBulkDeleteMocks = () => {
-  fetchMock.delete(
-    API_ENDPOINTS.DATASET_BULK_DELETE,
-    { message: '3 datasets deleted successfully' },
-    { overwriteRoutes: true },
-  );
+  fetchMock.delete(API_ENDPOINTS.DATASET_BULK_DELETE, {
+    message: '3 datasets deleted successfully',
+  });
 };
 
 // Setup error mocks for negative flow testing
@@ -439,25 +428,17 @@ export const setupDeleteErrorMocks = (
   datasetId: number,
   statusCode: number,
 ) => {
-  fetchMock.get(
-    `glob:*/api/v1/dataset/${datasetId}/related_objects*`,
-    {
-      status: statusCode,
-      body: { message: 'Failed to fetch related objects' },
-    },
-    { overwriteRoutes: true },
-  );
+  fetchMock.get(`glob:*/api/v1/dataset/${datasetId}/related_objects*`, {
+    status: statusCode,
+    body: { message: 'Failed to fetch related objects' },
+  });
 };
 
 export const setupDuplicateErrorMocks = (statusCode: number) => {
-  fetchMock.post(
-    API_ENDPOINTS.DATASET_DUPLICATE,
-    {
-      status: statusCode,
-      body: { message: 'Failed to duplicate dataset' },
-    },
-    { overwriteRoutes: true },
-  );
+  fetchMock.post(API_ENDPOINTS.DATASET_DUPLICATE, {
+    status: statusCode,
+    body: { message: 'Failed to duplicate dataset' },
+  });
 };
 
 /**
@@ -468,11 +449,13 @@ export const setupDuplicateErrorMocks = (statusCode: 
number) => {
  * @throws If any unmocked endpoints were called or expected endpoints weren't 
called
  */
 export const assertOnlyExpectedCalls = (expectedEndpoints: string[]) => {
-  const allCalls = fetchMock.calls(true); // Get all calls including unmatched
-  const unmatchedCalls = allCalls.filter(call => call.isUnmatched);
+  const allCalls = fetchMock.callHistory.calls();
+  const unmatchedCalls = allCalls.filter(
+    call => call.route?.config?.name === 'unmatched',
+  );
 
   if (unmatchedCalls.length > 0) {
-    const unmatchedUrls = unmatchedCalls.map(call => call[0]);
+    const unmatchedUrls = unmatchedCalls.map(call => call.url);
     throw new Error(
       `Unmocked endpoints called: ${unmatchedUrls.join(', ')}. ` +
         'Add explicit mocks in setupMocks() or test setup.',
@@ -481,7 +464,7 @@ export const assertOnlyExpectedCalls = (expectedEndpoints: 
string[]) => {
 
   // Verify expected endpoints were called
   expectedEndpoints.forEach(endpoint => {
-    const calls = fetchMock.calls(endpoint);
+    const calls = fetchMock.callHistory.calls(endpoint);
     if (calls.length === 0) {
       throw new Error(
         `Expected endpoint not called: ${endpoint}. ` +
@@ -493,7 +476,7 @@ export const assertOnlyExpectedCalls = (expectedEndpoints: 
string[]) => {
 
 // MSW setup using fetch-mock (following ChartList pattern)
 export const setupMocks = () => {
-  fetchMock.reset();
+  fetchMock.removeRoutes();
 
   fetchMock.get(API_ENDPOINTS.DATASETS_INFO, {
     permissions: ['can_read', 'can_write', 'can_export', 'can_duplicate'],

Reply via email to