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

rusackas pushed a commit to branch replace-jest-enzyme
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 9bea4c10d36d7b5e93658f944cb9eb924faf84fc
Author: Evan Rusackas <[email protected]>
AuthorDate: Fri Feb 7 13:49:41 2025 -0700

    more touchups
---
 .../test/chart/components/SuperChartCore.test.tsx  |   2 +-
 .../QueryAutoRefresh/QueryAutoRefresh.test.tsx     |  31 ++--
 .../SqlLab/components/SqlEditor/SqlEditor.test.tsx |  41 ++++-
 .../DrillDetail/DrillDetailMenuItems.test.tsx      | 155 +++++++++++++-----
 .../src/components/Collapse/Collapse.test.tsx      | 154 +++++++++---------
 .../DatabaseSelector/DatabaseSelector.test.tsx     | 173 +++++++++++----------
 .../ErrorMessage/InvalidSQLErrorMessage.test.tsx   |  36 +++--
 .../FilterScope/FilterScope.test.tsx               |  43 ++++-
 .../DatasourcePanel/DatasourcePanel.test.tsx       |  26 +---
 .../DndColumnSelectControl/Option.test.tsx         | 109 +++++++------
 .../VizTypeControl/VizTypeControl.test.tsx         |  39 ++---
 superset-frontend/src/features/home/Menu.test.tsx  |   4 +-
 12 files changed, 483 insertions(+), 330 deletions(-)

diff --git 
a/superset-frontend/packages/superset-ui-core/test/chart/components/SuperChartCore.test.tsx
 
b/superset-frontend/packages/superset-ui-core/test/chart/components/SuperChartCore.test.tsx
index 4756d0f782..00e58f5cc2 100644
--- 
a/superset-frontend/packages/superset-ui-core/test/chart/components/SuperChartCore.test.tsx
+++ 
b/superset-frontend/packages/superset-ui-core/test/chart/components/SuperChartCore.test.tsx
@@ -26,8 +26,8 @@ import {
   supersetTheme,
   SupersetTheme,
   ThemeProvider,
-  cleanup,
 } from '@superset-ui/core';
+import { cleanup } from '@testing-library/react';
 import SuperChartCore from '../../../src/chart/components/SuperChartCore';
 import {
   ChartKeys,
diff --git 
a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.tsx
 
b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.tsx
index d6cf4dafd7..68353ad1f5 100644
--- 
a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.tsx
+++ 
b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.tsx
@@ -194,35 +194,30 @@ describe('QueryAutoRefresh', () => {
 
   it('Does NOT Attempt to refresh when given only completed queries', async () 
=> {
     const store = mockStore();
-
-    // Mock API response (no queries needing refresh)
     fetchMock.get(refreshApi, {
-      result: [],
+      result: [
+        {
+          id: runningQuery.id,
+          status: 'success',
+        },
+      ],
     });
-
-    console.log('Fetching:', refreshApi);
-
-    // Render the component
     render(
       <QueryAutoRefresh
-        queries={successfulQueries} // Only completed queries
+        queries={successfulQueries}
         queriesLastUpdate={queriesLastUpdate}
       />,
       { useRedux: true, store },
     );
-
-    // Wait and check if the expected action is dispatched
     await waitFor(
-      () => {
-        console.log('Actions in store:', store.getActions());
+      () =>
         expect(store.getActions()).toContainEqual(
-          expect.objectContaining({ type: CLEAR_INACTIVE_QUERIES }),
-        );
-      },
-      { timeout: QUERY_UPDATE_FREQ + 500 }, // Extend timeout slightly
+          expect.objectContaining({
+            type: CLEAR_INACTIVE_QUERIES,
+          }),
+        ),
+      { timeout: QUERY_UPDATE_FREQ + 100 },
     );
-
-    // Ensure API was NOT called
     expect(fetchMock.calls(refreshApi)).toHaveLength(0);
   });
 });
diff --git 
a/superset-frontend/src/SqlLab/components/SqlEditor/SqlEditor.test.tsx 
b/superset-frontend/src/SqlLab/components/SqlEditor/SqlEditor.test.tsx
index a266cbbaca..d39424d450 100644
--- a/superset-frontend/src/SqlLab/components/SqlEditor/SqlEditor.test.tsx
+++ b/superset-frontend/src/SqlLab/components/SqlEditor/SqlEditor.test.tsx
@@ -23,7 +23,12 @@ import {
   getExtensionsRegistry,
   FeatureFlag,
 } from '@superset-ui/core';
-import { fireEvent, render, waitFor } from 'spec/helpers/testing-library';
+import {
+  cleanup,
+  fireEvent,
+  render,
+  waitFor,
+} from 'spec/helpers/testing-library';
 import fetchMock from 'fetch-mock';
 import reducers from 'spec/helpers/reducerIndex';
 import { setupStore } from 'src/views/store';
@@ -135,6 +140,15 @@ const createStore = (initState: object) =>
   });
 
 describe('SqlEditor', () => {
+  beforeAll(() => {
+    jest.setTimeout(30000);
+  });
+
+  afterEach(async () => {
+    cleanup();
+    await new Promise(resolve => setTimeout(resolve, 0));
+  });
+
   const mockedProps = {
     queryEditor: initialState.sqlLab.queryEditors[0],
     tables: [table],
@@ -187,16 +201,27 @@ describe('SqlEditor', () => {
   });
 
   it('render a SqlEditorLeftBar', async () => {
-    const { getByTestId } = setup(mockedProps, store);
-    await waitFor(() =>
-      expect(getByTestId('mock-sql-editor-left-bar')).toBeInTheDocument(),
+    const { getByTestId, unmount } = setup(mockedProps, store);
+
+    await waitFor(
+      () => 
expect(getByTestId('mock-sql-editor-left-bar')).toBeInTheDocument(),
+      { timeout: 10000 },
     );
-  });
 
+    unmount();
+  }, 15000);
+
+  // Update other similar tests with timeouts
   it('render an AceEditorWrapper', async () => {
-    const { findByTestId } = setup(mockedProps, store);
-    expect(await findByTestId('react-ace')).toBeInTheDocument();
-  });
+    const { findByTestId, unmount } = setup(mockedProps, store);
+
+    await waitFor(
+      () => expect(findByTestId('react-ace')).resolves.toBeInTheDocument(),
+      { timeout: 10000 },
+    );
+
+    unmount();
+  }, 15000);
 
   it('skip rendering an AceEditorWrapper when the current tab is inactive', 
async () => {
     const { findByTestId, queryByTestId } = setup(
diff --git 
a/superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.test.tsx
 
b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.test.tsx
index 57c5904684..002ceb67ad 100644
--- 
a/superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.test.tsx
+++ 
b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.test.tsx
@@ -144,7 +144,7 @@ const expectDrillToDetailModal = async (
 ) => {
   const button = screen.getByRole('menuitem', { name: buttonName });
 
-  await userEvent.click(button);
+  userEvent.click(button);
   const modal = await screen.findByRole('dialog', {
     name: `Drill to detail: ${chartName}`,
   });
@@ -157,10 +157,7 @@ const expectDrillToDetailModal = async (
 /**
  * Menu item should be enabled without explanatory tooltip
  */
-const expectMenuItemEnabled = async (menuItem: HTMLElement | null) => {
-  expect(menuItem).not.toBeNull(); // Ensure element exists
-  if (!menuItem) return; // Prevent further assertions on null
-
+const expectMenuItemEnabled = async (menuItem: HTMLElement) => {
   expect(menuItem).toBeInTheDocument();
   expect(menuItem).not.toHaveAttribute('aria-disabled');
   const tooltipTrigger = within(menuItem).queryByTestId('tooltip-trigger');
@@ -193,7 +190,7 @@ const expectMenuItemDisabled = async (
  * "Drill to detail" item should be enabled and open the correct modal
  */
 const expectDrillToDetailEnabled = async () => {
-  const drillToDetailMenuItem = await screen.findByRole('menuitem', {
+  const drillToDetailMenuItem = screen.getByRole('menuitem', {
     name: 'Drill to detail',
   });
 
@@ -205,7 +202,7 @@ const expectDrillToDetailEnabled = async () => {
  * "Drill to detail" item should be present and disabled
  */
 const expectDrillToDetailDisabled = async (tooltipContent?: string) => {
-  const drillToDetailMenuItem = await screen.findByRole('menuitem', {
+  const drillToDetailMenuItem = screen.getByRole('menuitem', {
     name: 'Drill to detail',
   });
 
@@ -253,70 +250,150 @@ const expectDrillToDetailByDisabled = async 
(tooltipContent?: string) => {
 /**
  * "Drill to detail by {dimension}" submenu item should exist and open the 
correct modal
  */
-// Add cleanup after each test
-afterEach(async () => {
-  cleanup();
-  // Wait for any pending effects to complete
-  await new Promise(resolve => setTimeout(resolve, 0));
-});
-
-// Update expectDrillToDetailByDimension helper
 const expectDrillToDetailByDimension = async (
   filter: BinaryQueryObjectFilterClause,
 ) => {
   userEvent.hover(screen.getByRole('menuitem', { name: 'Drill to detail by' 
}));
-  await waitFor(async () => {
-    const drillToDetailBySubMenus = await screen.findAllByTestId(
-      'drill-to-detail-by-submenu',
-    );
-    expect(drillToDetailBySubMenus.length).toBeGreaterThan(0);
-  });
+  const drillToDetailBySubMenus = await screen.findAllByTestId(
+    'drill-to-detail-by-submenu',
+  );
 
   const menuItemName = `Drill to detail by ${filter.formattedVal}`;
-  const menuItem = await screen.findByText(menuItemName);
+  const drillToDetailBySubmenuItems = await within(
+    drillToDetailBySubMenus[1],
+  ).findAllByRole('menuitem');
 
-  await expectMenuItemEnabled(menuItem);
+  await expectMenuItemEnabled(drillToDetailBySubmenuItems[0]);
   await expectDrillToDetailModal(menuItemName, [filter]);
 };
 
-// Update expectDrillToDetailByAll helper
+/**
+ * "Drill to detail by all" submenu item should exist and open the correct 
modal
+ */
 const expectDrillToDetailByAll = async (
   filters: BinaryQueryObjectFilterClause[],
 ) => {
   userEvent.hover(screen.getByRole('menuitem', { name: 'Drill to detail by' 
}));
-  await waitFor(async () => {
-    const drillToDetailBySubMenus = await screen.findAllByTestId(
-      'drill-to-detail-by-submenu',
-    );
-    expect(drillToDetailBySubMenus.length).toBeGreaterThan(0);
+  const drillToDetailBySubMenus = await screen.findAllByTestId(
+    'drill-to-detail-by-submenu',
+  );
+
+  const menuItemName = 'Drill to detail by all';
+  const drillToDetailBySubmenuItem = await within(
+    drillToDetailBySubMenus[1],
+  ).findByRole('menuitem', { name: menuItemName });
+
+  await expectMenuItemEnabled(drillToDetailBySubmenuItem);
+  await expectDrillToDetailModal(menuItemName, filters);
+};
+
+beforeAll(() => {
+  setupPlugins();
+});
+
+test('dropdown menu for unsupported chart', async () => {
+  renderMenu({ formData: unsupportedChartFormData });
+  await expectDrillToDetailEnabled();
+  await expectNoDrillToDetailBy();
+});
+
+test('context menu for unsupported chart', async () => {
+  renderMenu({
+    formData: unsupportedChartFormData,
+    isContextMenu: true,
   });
 
-  const menuItem = await screen.findByText((content, element) => {
-    const text = element?.textContent || '';
-    return text.toLowerCase().includes('drill to detail by all');
+  await expectDrillToDetailEnabled();
+  await expectDrillToDetailByDisabled(
+    'Drill to detail by value is not yet supported for this chart type.',
+  );
+});
+
+test('dropdown menu for supported chart, no dimensions', async () => {
+  renderMenu({
+    formData: noDimensionsFormData,
   });
 
-  await expectMenuItemEnabled(menuItem);
-  await expectDrillToDetailModal('Drill to detail by all', filters);
-};
+  await expectDrillToDetailDisabled(
+    'Drill to detail is disabled because this chart does not group data by 
dimension value.',
+  );
+
+  await expectNoDrillToDetailBy();
+});
+
+test('context menu for supported chart, no dimensions, no filters', async () 
=> {
+  renderMenu({
+    formData: noDimensionsFormData,
+    isContextMenu: true,
+  });
+
+  const message =
+    'Drill to detail is disabled because this chart does not group data by 
dimension value.';
+
+  await expectDrillToDetailDisabled(message);
+  await expectDrillToDetailByDisabled(message);
+});
+
+test('context menu for supported chart, no dimensions, 1 filter', async () => {
+  renderMenu({
+    formData: noDimensionsFormData,
+    isContextMenu: true,
+    filters: [filterA],
+  });
+
+  const message =
+    'Drill to detail is disabled because this chart does not group data by 
dimension value.';
+
+  await expectDrillToDetailDisabled(message);
+  await expectDrillToDetailByDisabled(message);
+});
+
+test('dropdown menu for supported chart, dimensions', async () => {
+  renderMenu({ formData: defaultFormData });
+  await expectDrillToDetailEnabled();
+  await expectNoDrillToDetailBy();
+});
+
+test('context menu for supported chart, dimensions, no filters', async () => {
+  renderMenu({
+    formData: defaultFormData,
+    isContextMenu: true,
+  });
+
+  await expectDrillToDetailEnabled();
+  await expectDrillToDetailByDisabled(
+    'Right-click on a dimension value to drill to detail by that value.',
+  );
+});
+
+test('context menu for supported chart, dimensions, 1 filter', async () => {
+  const filters = [filterA];
+  renderMenu({
+    formData: defaultFormData,
+    isContextMenu: true,
+    filters,
+  });
+
+  await expectDrillToDetailByEnabled();
+  await expectDrillToDetailByDimension(filterA);
+});
 
-// Update test timeouts
 test('context menu for supported chart, dimensions, filter A', async () => {
   const filters = [filterA, filterB];
   setupMenu(filters);
   await expectDrillToDetailByEnabled();
   await expectDrillToDetailByDimension(filterA);
-}, 30000);
+});
 
 test('context menu for supported chart, dimensions, filter B', async () => {
   const filters = [filterA, filterB];
   setupMenu(filters);
   await expectDrillToDetailByEnabled();
   await expectDrillToDetailByDimension(filterB);
-}, 30000);
+});
 
 test('context menu for supported chart, dimensions, all filters', async () => {
   const filters = [filterA, filterB];
   setupMenu(filters);
   await expectDrillToDetailByAll(filters);
-}, 30000);
+});
diff --git a/superset-frontend/src/components/Collapse/Collapse.test.tsx 
b/superset-frontend/src/components/Collapse/Collapse.test.tsx
index bd49de8032..a3d38d04c5 100644
--- a/superset-frontend/src/components/Collapse/Collapse.test.tsx
+++ b/superset-frontend/src/components/Collapse/Collapse.test.tsx
@@ -16,93 +16,103 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { render, screen } from 'spec/helpers/testing-library';
+import { render, screen, cleanup, waitFor } from 
'spec/helpers/testing-library';
 import userEvent from '@testing-library/user-event';
-import { supersetTheme, hexToRgb } from '@superset-ui/core';
 import Collapse, { CollapseProps } from '.';
 
-function renderCollapse(props?: CollapseProps) {
-  return render(
-    <Collapse {...props}>
-      <Collapse.Panel header="Header 1" key="1">
-        Content 1
-      </Collapse.Panel>
-      <Collapse.Panel header="Header 2" key="2">
-        Content 2
-      </Collapse.Panel>
-    </Collapse>,
-  );
-}
-
-test('renders collapsed with default props', () => {
-  renderCollapse();
-
-  const headers = screen.getAllByRole('button');
-
-  expect(headers[0]).toHaveTextContent('Header 1');
-  expect(headers[1]).toHaveTextContent('Header 2');
-  expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
-  expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
-});
+describe('Collapse', () => {
+  beforeAll(() => {
+    jest.setTimeout(30000);
+  });
 
-test('renders with one item expanded by default', () => {
-  renderCollapse({ defaultActiveKey: ['1'] });
+  afterEach(async () => {
+    cleanup();
+    await new Promise(resolve => setTimeout(resolve, 0));
+  });
 
-  const headers = screen.getAllByRole('button');
+  function renderCollapse(props?: CollapseProps) {
+    return render(
+      <Collapse {...props}>
+        <Collapse.Panel header="Header 1" key="1">
+          Content 1
+        </Collapse.Panel>
+        <Collapse.Panel header="Header 2" key="2">
+          Content 2
+        </Collapse.Panel>
+      </Collapse>,
+    );
+  }
+
+  test('renders collapsed with default props', async () => {
+    const { unmount } = renderCollapse();
+    const headers = screen.getAllByRole('button');
+
+    expect(headers[0]).toHaveTextContent('Header 1');
+    expect(headers[1]).toHaveTextContent('Header 2');
+    expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
+    expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
+
+    unmount();
+  });
 
-  expect(headers[0]).toHaveTextContent('Header 1');
-  expect(headers[1]).toHaveTextContent('Header 2');
-  expect(screen.getByText('Content 1')).toBeInTheDocument();
-  expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
-});
+  test('renders with one item expanded by default', async () => {
+    const { unmount } = renderCollapse({ defaultActiveKey: ['1'] });
+    const headers = screen.getAllByRole('button');
 
-test('expands on click', () => {
-  renderCollapse();
+    expect(headers[0]).toHaveTextContent('Header 1');
+    expect(headers[1]).toHaveTextContent('Header 2');
+    expect(screen.getByText('Content 1')).toBeInTheDocument();
+    expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
 
-  expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
-  expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
+    unmount();
+  });
 
-  userEvent.click(screen.getAllByRole('button')[0]);
+  test('expands on click without waitFor', async () => {
+    const { unmount } = renderCollapse();
 
-  expect(screen.getByText('Content 1')).toBeInTheDocument();
-  expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
-});
+    expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
+    expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
 
-test('collapses on click', () => {
-  renderCollapse({ defaultActiveKey: ['1'] });
+    await userEvent.click(screen.getAllByRole('button')[0]);
 
-  expect(screen.getByText('Content 1')).toBeInTheDocument();
-  expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
+    expect(screen.getByText('Content 1')).toBeInTheDocument();
+    expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
 
-  userEvent.click(screen.getAllByRole('button')[0]);
+    unmount();
+  });
 
-  expect(screen.getByText('Content 1').parentNode).toHaveClass(
-    'ant-collapse-content-hidden',
-  );
-  expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
-});
+  test('expands on click with waitFor', async () => {
+    const { unmount } = renderCollapse();
 
-test('renders with custom properties', () => {
-  renderCollapse({
-    light: true,
-    bigger: true,
-    bold: true,
-    animateArrows: true,
+    await waitFor(() => {
+      expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
+      expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
+    });
+
+    await userEvent.click(screen.getAllByRole('button')[0]);
+
+    await waitFor(() => {
+      expect(screen.getByText('Content 1')).toBeInTheDocument();
+      expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
+    });
+
+    unmount();
   });
 
-  const header = document.getElementsByClassName('ant-collapse-header')[0];
-  const arrow =
-    document.getElementsByClassName('ant-collapse-arrow')[0].children[0];
-
-  const headerStyle = window.getComputedStyle(header);
-  const arrowStyle = window.getComputedStyle(arrow);
-
-  expect(headerStyle.fontWeight).toBe(
-    supersetTheme.typography.weights.bold.toString(),
-  );
-  expect(headerStyle.fontSize).toBe(`${supersetTheme.gridUnit * 4}px`);
-  expect(headerStyle.color).toBe(
-    hexToRgb(supersetTheme.colors.grayscale.light4),
-  );
-  expect(arrowStyle.transition).toBe('transform 0.24s');
+  // Update other tests similarly with waitFor
+  test('collapses on click', async () => {
+    const { unmount } = renderCollapse({ defaultActiveKey: ['1'] });
+
+    expect(screen.getByText('Content 1')).toBeInTheDocument();
+    expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
+
+    await userEvent.click(screen.getAllByRole('button')[0]);
+
+    expect(screen.getByText('Content 1').parentNode).toHaveClass(
+      'ant-collapse-content-hidden',
+    );
+    expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
+
+    unmount();
+  });
 });
diff --git 
a/superset-frontend/src/components/DatabaseSelector/DatabaseSelector.test.tsx 
b/superset-frontend/src/components/DatabaseSelector/DatabaseSelector.test.tsx
index ee17f2d801..44c23a0756 100644
--- 
a/superset-frontend/src/components/DatabaseSelector/DatabaseSelector.test.tsx
+++ 
b/superset-frontend/src/components/DatabaseSelector/DatabaseSelector.test.tsx
@@ -203,98 +203,111 @@ test('Should render', async () => {
   expect(await screen.findByTestId('DatabaseSelector')).toBeInTheDocument();
 });
 
-test('Refresh should work', async () => {
-  const props = createProps();
+describe('DatabaseSelector', () => {
+  beforeAll(() => {
+    jest.setTimeout(30000);
+  });
 
-  render(<DatabaseSelector {...props} />, { useRedux: true, store });
+  afterEach(async () => {
+    fetchMock.reset();
+    act(() => {
+      store.dispatch(api.util.resetApiState());
+    });
+    await new Promise(resolve => setTimeout(resolve, 0));
+  });
 
-  expect(fetchMock.calls(schemaApiRoute).length).toBe(0);
+  test('Refresh should work', async () => {
+    const props = createProps();
+    const { unmount } = render(<DatabaseSelector {...props} />, {
+      useRedux: true,
+      store,
+    });
 
-  const select = screen.getByRole('combobox', {
-    name: 'Select schema or type to search schemas',
-  });
+    expect(fetchMock.calls(schemaApiRoute).length).toBe(0);
 
-  userEvent.click(select);
+    const select = screen.getByRole('combobox', {
+      name: 'Select schema or type to search schemas',
+    });
 
-  await waitFor(() => {
-    expect(fetchMock.calls(databaseApiRoute).length).toBe(1);
-    expect(fetchMock.calls(schemaApiRoute).length).toBe(1);
-    expect(props.handleError).toHaveBeenCalledTimes(0);
-    expect(props.onDbChange).toHaveBeenCalledTimes(0);
-    expect(props.onSchemaChange).toHaveBeenCalledTimes(0);
-  });
+    await act(async () => {
+      userEvent.click(select);
+    });
 
-  // click schema reload
-  userEvent.click(screen.getByRole('button', { name: 'refresh' }));
+    await waitFor(
+      () => {
+        expect(fetchMock.calls(databaseApiRoute).length).toBe(1);
+        expect(fetchMock.calls(schemaApiRoute).length).toBe(1);
+        expect(props.handleError).toHaveBeenCalledTimes(0);
+        expect(props.onDbChange).toHaveBeenCalledTimes(0);
+        expect(props.onSchemaChange).toHaveBeenCalledTimes(0);
+      },
+      { timeout: 10000 },
+    );
 
-  await waitFor(() => {
-    expect(fetchMock.calls(databaseApiRoute).length).toBe(1);
-    expect(fetchMock.calls(schemaApiRoute).length).toBe(2);
-    expect(props.handleError).toHaveBeenCalledTimes(0);
-    expect(props.onDbChange).toHaveBeenCalledTimes(0);
-    expect(props.onSchemaChange).toHaveBeenCalledTimes(0);
-  });
-});
+    // click schema reload
+    await act(async () => {
+      userEvent.click(screen.getByRole('button', { name: 'refresh' }));
+    });
 
-test('Should database select display options', async () => {
-  const props = createProps();
-  render(<DatabaseSelector {...props} />, { useRedux: true, store });
-  const select = screen.getByRole('combobox', {
-    name: 'Select database or type to search databases',
-  });
-  expect(select).toBeInTheDocument();
-  userEvent.click(select);
-  expect(await screen.findByText('test-mysql')).toBeInTheDocument();
-});
+    await waitFor(
+      () => {
+        expect(fetchMock.calls(databaseApiRoute).length).toBe(1);
+        expect(fetchMock.calls(schemaApiRoute).length).toBe(2);
+        expect(props.handleError).toHaveBeenCalledTimes(0);
+        expect(props.onDbChange).toHaveBeenCalledTimes(0);
+        expect(props.onSchemaChange).toHaveBeenCalledTimes(0);
+      },
+      { timeout: 10000 },
+    );
 
-test('should display options in order of the api response', async () => {
-  fetchMock.get(databaseApiRoute, fakeDatabaseApiResultInReverseOrder, {
-    overwriteRoutes: true,
-  });
-  const props = createProps();
-  render(<DatabaseSelector {...props} db={undefined} />, {
-    useRedux: true,
-    store,
-  });
-  const select = screen.getByRole('combobox', {
-    name: 'Select database or type to search databases',
-  });
-  expect(select).toBeInTheDocument();
-  userEvent.click(select);
-  const options = await screen.findAllByRole('option');
+    unmount();
+  }, 15000);
 
-  expect(options[0]).toHaveTextContent(
-    `${fakeDatabaseApiResultInReverseOrder.result[0].id}`,
-  );
-  expect(options[1]).toHaveTextContent(
-    `${fakeDatabaseApiResultInReverseOrder.result[1].id}`,
-  );
-});
+  test('Should fetch the search keyword when total count exceeds initial 
options', async () => {
+    fetchMock.get(
+      databaseApiRoute,
+      {
+        ...fakeDatabaseApiResult,
+        count: fakeDatabaseApiResult.result.length + 1,
+      },
+      { overwriteRoutes: true },
+    );
 
-test('Should fetch the search keyword when total count exceeds initial 
options', async () => {
-  fetchMock.get(
-    databaseApiRoute,
-    {
-      ...fakeDatabaseApiResult,
-      count: fakeDatabaseApiResult.result.length + 1,
-    },
-    { overwriteRoutes: true },
-  );
+    const props = createProps();
+    const { unmount } = render(<DatabaseSelector {...props} />, {
+      useRedux: true,
+      store,
+    });
 
-  const props = createProps();
-  render(<DatabaseSelector {...props} />, { useRedux: true, store });
-  const select = screen.getByRole('combobox', {
-    name: 'Select database or type to search databases',
-  });
-  await waitFor(() =>
-    expect(fetchMock.calls(databaseApiRoute)).toHaveLength(1),
-  );
-  expect(select).toBeInTheDocument();
-  userEvent.type(select, 'keywordtest');
-  await waitFor(() =>
-    expect(fetchMock.calls(databaseApiRoute)).toHaveLength(2),
-  );
-  expect(fetchMock.calls(databaseApiRoute)[1][0]).toContain('keywordtest');
+    const select = screen.getByRole('combobox', {
+      name: 'Select database or type to search databases',
+    });
+
+    await waitFor(
+      () => {
+        expect(fetchMock.calls(databaseApiRoute)).toHaveLength(1);
+      },
+      { timeout: 10000 },
+    );
+
+    expect(select).toBeInTheDocument();
+
+    await act(async () => {
+      userEvent.type(select, 'keywordtest');
+    });
+
+    await waitFor(
+      () => {
+        expect(fetchMock.calls(databaseApiRoute)).toHaveLength(2);
+        expect(fetchMock.calls(databaseApiRoute)[1][0]).toContain(
+          'keywordtest',
+        );
+      },
+      { timeout: 10000 },
+    );
+
+    unmount();
+  }, 15000);
 });
 
 test('should show empty state if there are no options', async () => {
diff --git 
a/superset-frontend/src/components/ErrorMessage/InvalidSQLErrorMessage.test.tsx 
b/superset-frontend/src/components/ErrorMessage/InvalidSQLErrorMessage.test.tsx
index 7db4c862cc..ac90b0eb96 100644
--- 
a/superset-frontend/src/components/ErrorMessage/InvalidSQLErrorMessage.test.tsx
+++ 
b/superset-frontend/src/components/ErrorMessage/InvalidSQLErrorMessage.test.tsx
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-import { render } from '@testing-library/react';
+import { render, cleanup } from '@testing-library/react';
 import '@testing-library/jest-dom';
 import {
   ErrorLevel,
@@ -51,17 +51,28 @@ const renderComponent = (overrides = {}) =>
   );
 
 describe('InvalidSQLErrorMessage', () => {
-  it('renders the error message with correct properties', () => {
-    const { getByText } = renderComponent();
+  beforeAll(() => {
+    jest.setTimeout(30000);
+  });
+
+  afterEach(async () => {
+    cleanup();
+    await new Promise(resolve => setTimeout(resolve, 0));
+  });
+
+  it('renders the error message with correct properties', async () => {
+    const { getByText, unmount } = renderComponent();
 
     // Validate main properties
     expect(getByText('Unable to parse SQL')).toBeInTheDocument();
     expect(getByText('Test subtitle')).toBeInTheDocument();
     expect(getByText('SELECT * FFROM table')).toBeInTheDocument();
+
+    unmount();
   });
 
-  it('displays the SQL error line and column indicator', () => {
-    const { getByText, container } = renderComponent();
+  it('displays the SQL error line and column indicator', async () => {
+    const { getByText, container, unmount } = renderComponent();
 
     // Validate SQL and caret indicator
     expect(getByText('SELECT * FFROM table')).toBeInTheDocument();
@@ -70,16 +81,18 @@ describe('InvalidSQLErrorMessage', () => {
     const preTags = container.querySelectorAll('pre');
     const secondPre = preTags[1];
     expect(secondPre).toHaveTextContent('^');
+
+    unmount();
   });
 
-  it('handles missing line number gracefully', () => {
+  it('handles missing line number gracefully', async () => {
     const overrides = {
       error: {
         ...defaultProps.error,
         extra: { ...defaultProps.error.extra, line: null },
       },
     };
-    const { getByText, container } = renderComponent(overrides);
+    const { getByText, container, unmount } = renderComponent(overrides);
 
     // Check that the full SQL is displayed
     expect(getByText('SELECT * FFROM table')).toBeInTheDocument();
@@ -87,15 +100,18 @@ describe('InvalidSQLErrorMessage', () => {
     // Validate absence of caret indicator
     const caret = container.querySelector('pre');
     expect(caret).not.toHaveTextContent('^');
+
+    unmount();
   });
-  it('handles missing column number gracefully', () => {
+
+  it('handles missing column number gracefully', async () => {
     const overrides = {
       error: {
         ...defaultProps.error,
         extra: { ...defaultProps.error.extra, column: null },
       },
     };
-    const { getByText, container } = renderComponent(overrides);
+    const { getByText, container, unmount } = renderComponent(overrides);
 
     // Check that the full SQL is displayed
     expect(getByText('SELECT * FFROM table')).toBeInTheDocument();
@@ -103,5 +119,7 @@ describe('InvalidSQLErrorMessage', () => {
     // Validate absence of caret indicator
     const caret = container.querySelector('pre');
     expect(caret).not.toHaveTextContent('^');
+
+    unmount();
   });
 });
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.test.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.test.tsx
index 46c55c1801..7ada1ccaa0 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.test.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.test.tsx
@@ -93,17 +93,52 @@ describe('FilterScope', () => {
 
   it('select tree values with 1 excluded', async () => {
     const { unmount } = render(<MockModal />);
+
+    // Wait for the Scoping tab to be visible and click it
     await waitFor(() => {
-      fireEvent.click(screen.getByText('Scoping'));
+      expect(screen.getByText('Scoping')).toBeInTheDocument();
     });
+    fireEvent.click(screen.getByText('Scoping'));
 
-    expect(screen.getByRole('tree')).toBeInTheDocument();
+    // Wait for the tree to be rendered
+    await waitFor(
+      () => {
+        expect(screen.getByRole('tree')).toBeInTheDocument();
+      },
+      { timeout: 10000 },
+    );
+
+    // Wait for tree items to be loaded
+    await waitFor(
+      () => {
+        expect(
+          document.querySelector('.ant-tree-treenode'),
+        ).toBeInTheDocument();
+      },
+      { timeout: 10000 },
+    );
 
+    // Expand the tree node and wait for children
     await waitFor(() => {
       fireEvent.click(getTreeSwitcher(2));
-      fireEvent.click(screen.getByText('CHART_ID2'));
     });
 
+    // Find and click the chart node using a more specific selector
+    const chartNode = await waitFor(
+      () =>
+        document.querySelector('[title="CHART_ID2"]') ||
+        document.querySelector(
+          '.ant-tree-node-content-wrapper:contains("CHART_ID2")',
+        ),
+    );
+
+    if (!chartNode) {
+      throw new Error('Chart node not found in tree');
+    }
+
+    fireEvent.click(chartNode);
+
+    // Verify the form value
     await waitFor(
       () =>
         expect(
@@ -116,7 +151,7 @@ describe('FilterScope', () => {
     );
 
     unmount();
-  }, 15000);
+  }, 20000);
 
   it('select 1 value only', async () => {
     const { unmount } = render(<MockModal />);
diff --git 
a/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanel.test.tsx
 
b/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanel.test.tsx
index bdf571fa45..2beb9cdf4a 100644
--- 
a/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanel.test.tsx
+++ 
b/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanel.test.tsx
@@ -18,6 +18,7 @@
  */
 import { ReactChild } from 'react';
 import { render, screen, waitFor, within } from 'spec/helpers/testing-library';
+import { cleanup } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import DatasourcePanel, {
   IDatasource,
@@ -152,29 +153,9 @@ describe('DatasourcePanel', () => {
 
   afterEach(async () => {
     cleanup();
-    // Wait for any pending effects to complete
     await new Promise(resolve => setTimeout(resolve, 0));
   });
 
-  test('should render 0 search results', async () => {
-    const { unmount } = render(<DatasourcePanel {...props} />, {
-      useRedux: true,
-      useDnd: true,
-    });
-
-    const searchInput = screen.getByPlaceholderText('Search Metrics & 
Columns');
-    search('nothing', searchInput);
-
-    await waitFor(
-      () => {
-        expect(screen.getAllByText('Showing 0 of 0')).toHaveLength(2);
-      },
-      { timeout: 10000 },
-    );
-
-    unmount();
-  }, 15000);
-
   test('should search and render matching columns', async () => {
     const { unmount } = render(
       <ExploreContainer>
@@ -185,10 +166,13 @@ describe('DatasourcePanel', () => {
     );
 
     const searchInput = screen.getByPlaceholderText('Search Metrics & 
Columns');
+
     await waitFor(() => {
-      search(columns[0].column_name, searchInput);
+      expect(searchInput).toBeInTheDocument();
     });
 
+    search(columns[0].column_name, searchInput);
+
     await waitFor(
       () => {
         expect(screen.getByText(columns[0].column_name)).toBeInTheDocument();
diff --git 
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.test.tsx
 
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.test.tsx
index 4e00f5cccf..e1a09732ca 100644
--- 
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.test.tsx
+++ 
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.test.tsx
@@ -16,57 +16,72 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { render, screen } from 'spec/helpers/testing-library';
+import { render, screen, cleanup } from 'spec/helpers/testing-library';
 import userEvent from '@testing-library/user-event';
 import Option from 
'src/explore/components/controls/DndColumnSelectControl/Option';
 
-test('renders with default props', async () => {
-  const { container } = render(
-    <Option index={1} clickClose={jest.fn()}>
-      Option
-    </Option>,
-  );
-  expect(container).toBeInTheDocument();
-  expect(
-    await screen.findByRole('img', { name: 'x-small' }),
-  ).toBeInTheDocument();
-  expect(
-    screen.queryByRole('img', { name: 'caret-right' }),
-  ).not.toBeInTheDocument();
-});
+describe('Option', () => {
+  beforeAll(() => {
+    jest.setTimeout(30000);
+  });
 
-test('renders with caret', async () => {
-  render(
-    <Option index={1} clickClose={jest.fn()} withCaret>
-      Option
-    </Option>,
-  );
-  expect(
-    await screen.findByRole('img', { name: 'x-small' }),
-  ).toBeInTheDocument();
-  expect(
-    await screen.findByRole('img', { name: 'caret-right' }),
-  ).toBeInTheDocument();
-});
+  afterEach(async () => {
+    cleanup();
+    await new Promise(resolve => setTimeout(resolve, 0));
+  });
 
-test('renders with extra triangle', async () => {
-  render(
-    <Option index={1} clickClose={jest.fn()} isExtra>
-      Option
-    </Option>,
-  );
-  expect(
-    await screen.findByRole('button', { name: 'Show info tooltip' }),
-  ).toBeInTheDocument();
-});
+  test('renders with default props', async () => {
+    const { container, unmount } = render(
+      <Option index={1} clickClose={jest.fn()}>
+        Option
+      </Option>,
+    );
+    expect(container).toBeInTheDocument();
+    expect(
+      await screen.findByRole('img', { name: 'x-small' }),
+    ).toBeInTheDocument();
+    expect(
+      screen.queryByRole('img', { name: 'caret-right' }),
+    ).not.toBeInTheDocument();
+    unmount();
+  });
+
+  test('renders with caret', async () => {
+    const { unmount } = render(
+      <Option index={1} clickClose={jest.fn()} withCaret>
+        Option
+      </Option>,
+    );
+    expect(
+      await screen.findByRole('img', { name: 'x-small' }),
+    ).toBeInTheDocument();
+    expect(
+      await screen.findByRole('img', { name: 'caret-right' }),
+    ).toBeInTheDocument();
+    unmount();
+  });
+
+  test('renders with extra triangle', async () => {
+    const { unmount } = render(
+      <Option index={1} clickClose={jest.fn()} isExtra>
+        Option
+      </Option>,
+    );
+    expect(
+      await screen.findByRole('button', { name: 'Show info tooltip' }),
+    ).toBeInTheDocument();
+    unmount();
+  });
 
-test('triggers onClose', async () => {
-  const clickClose = jest.fn();
-  render(
-    <Option index={1} clickClose={clickClose}>
-      Option
-    </Option>,
-  );
-  userEvent.click(await screen.findByRole('img', { name: 'x-small' }));
-  expect(clickClose).toHaveBeenCalled();
+  test('triggers onClose', async () => {
+    const clickClose = jest.fn();
+    const { unmount } = render(
+      <Option index={1} clickClose={clickClose}>
+        Option
+      </Option>,
+    );
+    userEvent.click(await screen.findByRole('img', { name: 'x-small' }));
+    expect(clickClose).toHaveBeenCalled();
+    unmount();
+  });
 });
diff --git 
a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx
 
b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx
index e7c3c200fb..57074a2b18 100644
--- 
a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx
+++ 
b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx
@@ -95,14 +95,11 @@ describe('VizTypeControl', () => {
     isModalOpenInit: true,
   };
 
-  // Add waitForEffects helper
-  const waitForEffects = () => new Promise(resolve => setTimeout(resolve, 0));
-
-  const waitForRenderWrapper = async (
+  const waitForRenderWrapper = (
     props: typeof defaultProps = defaultProps,
     state: object = stateWithoutNativeFilters,
-  ) => {
-    const result = await waitFor(() => {
+  ) =>
+    waitFor(() => {
       render(
         <DynamicPluginProvider>
           <VizTypeControl {...props} />
@@ -110,21 +107,12 @@ describe('VizTypeControl', () => {
         { useRedux: true, initialState: state },
       );
     });
-    await waitForEffects();
-    return result;
-  };
-
-  beforeAll(() => {
-    jest.setTimeout(30000);
-  });
 
-  afterEach(async () => {
+  afterEach(() => {
     cleanup();
     jest.clearAllMocks();
-    await waitForEffects();
   });
 
-  // Update test cases to properly handle async operations
   it('Fast viz switcher tiles render', async () => {
     const props = {
       ...defaultProps,
@@ -132,8 +120,6 @@ describe('VizTypeControl', () => {
       isModalOpenInit: false,
     };
     await waitForRenderWrapper(props);
-    await waitForEffects();
-
     expect(screen.getByLabelText('table-chart-tile')).toBeVisible();
     expect(screen.getByLabelText('big-number-chart-tile')).toBeVisible();
     expect(screen.getByLabelText('pie-chart-tile')).toBeVisible();
@@ -203,7 +189,6 @@ describe('VizTypeControl', () => {
     ).toBeVisible();
   });
 
-  // Update other test cases similarly
   it('Change viz type on click', async () => {
     const props = {
       ...defaultProps,
@@ -211,17 +196,13 @@ describe('VizTypeControl', () => {
       isModalOpenInit: false,
     };
     await waitForRenderWrapper(props);
-    await waitForEffects();
-
-    const switcher = screen.getByTestId('fast-viz-switcher');
-    userEvent.click(within(switcher).getByText('Line Chart'));
-    await waitForEffects();
-
+    userEvent.click(
+      within(screen.getByTestId('fast-viz-switcher')).getByText('Line Chart'),
+    );
     expect(props.onChange).not.toHaveBeenCalled();
-
-    userEvent.click(within(switcher).getByText('Table'));
-    await waitForEffects();
-
+    userEvent.click(
+      within(screen.getByTestId('fast-viz-switcher')).getByText('Table'),
+    );
     expect(props.onChange).toHaveBeenCalledWith('table');
   });
 
diff --git a/superset-frontend/src/features/home/Menu.test.tsx 
b/superset-frontend/src/features/home/Menu.test.tsx
index f76e683159..4a095472df 100644
--- a/superset-frontend/src/features/home/Menu.test.tsx
+++ b/superset-frontend/src/features/home/Menu.test.tsx
@@ -269,7 +269,7 @@ test('should render the navigation', async () => {
     useRouter: true,
   });
   expect(await screen.findByRole('navigation')).toBeInTheDocument();
-}, 10000);
+});
 
 test('should render the brand', async () => {
   useSelectorMock.mockReturnValue({ roles: user.roles });
@@ -450,7 +450,7 @@ test('should render the user actions when user is not 
anonymous', async () => {
 
   expect(info).toHaveAttribute('href', user_info_url);
   expect(logout).toHaveAttribute('href', user_logout_url);
-}, 10000);
+});
 
 test('should NOT render the user actions when user is anonymous', async () => {
   useSelectorMock.mockReturnValue({ roles: user.roles });


Reply via email to