You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by jl...@apache.org on 2025/10/09 21:44:45 UTC
(superset) branch remove-jsx-tests created (now 7d8b707da5)
This is an automated email from the ASF dual-hosted git repository.
jli pushed a change to branch remove-jsx-tests
in repository https://gitbox.apache.org/repos/asf/superset.git
at 7d8b707da5 test: migrate 3 JSX test files to TypeScript
This branch includes the following new commits:
new 7d8b707da5 test: migrate 3 JSX test files to TypeScript
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(superset) 01/01: test: migrate 3 JSX test files to TypeScript
Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jli pushed a commit to branch remove-jsx-tests
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 7d8b707da572d7f883d1f7340516564d326bb683
Author: Joe Li <jo...@preset.io>
AuthorDate: Thu Oct 9 14:42:57 2025 -0700
test: migrate 3 JSX test files to TypeScript
- Merged ListView.test.jsx comprehensive tests into ListView.test.tsx (9 tests total)
- Removed DatasourceControl.test.jsx (all tests already in .tsx with 21 tests)
- Removed VizTypeControl.test.jsx (all tests already in .tsx with 10 tests)
All 40 tests pass. TypeScript migration aligns with frontend modernization goals.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <no...@anthropic.com>
---
.../src/components/ListView/ListView.test.jsx | 271 ---------------------
.../src/components/ListView/ListView.test.tsx | 262 +++++++++++++++++++-
.../DatasourceControl/DatasourceControl.test.jsx | 170 -------------
.../VizTypeControl/VizTypeControl.test.jsx | 131 ----------
4 files changed, 259 insertions(+), 575 deletions(-)
diff --git a/superset-frontend/src/components/ListView/ListView.test.jsx b/superset-frontend/src/components/ListView/ListView.test.jsx
deleted file mode 100644
index 4045c4b85c..0000000000
--- a/superset-frontend/src/components/ListView/ListView.test.jsx
+++ /dev/null
@@ -1,271 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import { render, screen, within, waitFor } from 'spec/helpers/testing-library';
-import userEvent from '@testing-library/user-event';
-import { QueryParamProvider } from 'use-query-params';
-import thunk from 'redux-thunk';
-import configureStore from 'redux-mock-store';
-import fetchMock from 'fetch-mock';
-
-// Only import components that are directly referenced in tests
-import { ListView } from './ListView';
-
-const middlewares = [thunk];
-const mockStore = configureStore(middlewares);
-
-function makeMockLocation(query) {
- const queryStr = encodeURIComponent(query);
- return {
- protocol: 'http:',
- host: 'localhost',
- pathname: '/',
- search: queryStr.length ? `?${queryStr}` : '',
- };
-}
-
-const fetchSelectsMock = jest.fn(() => []);
-const mockedProps = {
- title: 'Data Table',
- columns: [
- {
- accessor: 'id',
- Header: 'ID',
- sortable: true,
- id: 'id',
- },
- {
- accessor: 'age',
- Header: 'Age',
- id: 'age',
- },
- {
- accessor: 'name',
- Header: 'Name',
- id: 'name',
- },
- {
- accessor: 'time',
- Header: 'Time',
- id: 'time',
- },
- ],
- filters: [
- {
- Header: 'ID',
- id: 'id',
- input: 'select',
- selects: [{ label: 'foo', value: 'bar' }],
- operator: 'eq',
- },
- {
- Header: 'Name',
- id: 'name',
- input: 'search',
- operator: 'ct',
- },
- {
- Header: 'Age',
- id: 'age',
- input: 'select',
- fetchSelects: fetchSelectsMock,
- paginate: true,
- operator: 'eq',
- },
- {
- Header: 'Time',
- id: 'time',
- input: 'datetime_range',
- operator: 'between',
- },
- ],
- data: [
- { id: 1, name: 'data 1', age: 10, time: '2020-11-18T07:53:45.354Z' },
- { id: 2, name: 'data 2', age: 1, time: '2020-11-18T07:53:45.354Z' },
- ],
- count: 2,
- pageSize: 1,
- fetchData: jest.fn(() => []),
- loading: false,
- bulkSelectEnabled: true,
- disableBulkSelect: jest.fn(),
- bulkActions: [
- {
- key: 'something',
- name: 'do something',
- style: 'danger',
- onSelect: jest.fn(),
- },
- ],
- cardSortSelectOptions: [
- {
- desc: false,
- id: 'something',
- label: 'Alphabetical',
- value: 'alphabetical',
- },
- ],
-};
-
-const factory = (props = mockedProps) =>
- render(
- <QueryParamProvider location={makeMockLocation()}>
- <ListView {...props} />
- </QueryParamProvider>,
- { store: mockStore() },
- );
-
-// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
-describe('ListView', () => {
- beforeEach(() => {
- fetchMock.reset();
- jest.clearAllMocks();
- factory();
- });
-
- afterEach(() => {
- fetchMock.reset();
- mockedProps.fetchData.mockClear();
- mockedProps.bulkActions.forEach(ba => {
- ba.onSelect.mockClear();
- });
- });
-
- // Example of converted test:
- test('calls fetchData on mount', () => {
- expect(mockedProps.fetchData).toHaveBeenCalledWith({
- filters: [],
- pageIndex: 0,
- pageSize: 1,
- sortBy: [],
- });
- });
-
- test('calls fetchData on sort', async () => {
- const sortHeader = screen.getAllByTestId('sort-header')[1];
- await userEvent.click(sortHeader);
-
- expect(mockedProps.fetchData).toHaveBeenCalledWith({
- filters: [],
- pageIndex: 0,
- pageSize: 1,
- sortBy: [
- {
- desc: false,
- id: 'id',
- },
- ],
- });
- });
-
- // Update pagination control tests for Ant Design pagination
- test('renders pagination controls', () => {
- const paginationList = screen.getByRole('list');
- expect(paginationList).toBeInTheDocument();
-
- const pageOneItem = screen.getByRole('listitem', { name: '1' });
- expect(pageOneItem).toBeInTheDocument();
- });
-
- test('calls fetchData on page change', async () => {
- const pageTwoItem = screen.getByRole('listitem', { name: '2' });
- await userEvent.click(pageTwoItem);
-
- await waitFor(() => {
- const { calls } = mockedProps.fetchData.mock;
- const pageChangeCall = calls.find(
- call =>
- call[0].pageIndex === 1 &&
- call[0].filters.length === 0 &&
- call[0].pageSize === 1,
- );
- expect(pageChangeCall).toBeDefined();
- });
- });
-
- test('handles bulk actions on 1 row', async () => {
- const checkboxes = screen.getAllByRole('checkbox');
- await userEvent.click(checkboxes[1]); // Index 1 is the first row checkbox
-
- const bulkActionButton = within(
- screen.getByTestId('bulk-select-controls'),
- ).getByTestId('bulk-select-action');
- await userEvent.click(bulkActionButton);
-
- expect(mockedProps.bulkActions[0].onSelect).toHaveBeenCalledWith([
- {
- age: 10,
- id: 1,
- name: 'data 1',
- time: '2020-11-18T07:53:45.354Z',
- },
- ]);
- });
-
- // Update UI filters test to use more specific selector
- test('renders UI filters', () => {
- const filterControls = screen.getAllByRole('combobox');
- expect(filterControls).toHaveLength(2);
- });
-
- test('calls fetchData on filter', async () => {
- // Handle select filter
- const selectFilter = screen.getAllByRole('combobox')[0];
- await userEvent.click(selectFilter);
- const option = screen.getByText('foo');
- await userEvent.click(option);
-
- // Handle search filter
- const searchFilter = screen.getByPlaceholderText('Type a value');
- await userEvent.type(searchFilter, 'something');
- await userEvent.tab();
-
- expect(mockedProps.fetchData).toHaveBeenCalledWith(
- expect.objectContaining({
- filters: [
- {
- id: 'id',
- operator: 'eq',
- value: { label: 'foo', value: 'bar' },
- },
- {
- id: 'name',
- operator: 'ct',
- value: 'something',
- },
- ],
- }),
- );
- });
-
- test('calls fetchData on card view sort', async () => {
- factory({
- ...mockedProps,
- renderCard: jest.fn(),
- initialSort: [{ id: 'something' }],
- });
-
- const sortSelect = screen.getByTestId('card-sort-select');
- await userEvent.click(sortSelect);
-
- const sortOption = screen.getByText('Alphabetical');
- await userEvent.click(sortOption);
-
- expect(mockedProps.fetchData).toHaveBeenCalled();
- });
-});
diff --git a/superset-frontend/src/components/ListView/ListView.test.tsx b/superset-frontend/src/components/ListView/ListView.test.tsx
index f40dc229fb..7cc8f4e9d9 100644
--- a/superset-frontend/src/components/ListView/ListView.test.tsx
+++ b/superset-frontend/src/components/ListView/ListView.test.tsx
@@ -16,10 +16,118 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { render, waitFor } from 'spec/helpers/testing-library';
+import { render, screen, within, waitFor } from 'spec/helpers/testing-library';
+import userEvent from '@testing-library/user-event';
+import { QueryParamProvider } from 'use-query-params';
+import thunk from 'redux-thunk';
+import configureStore from 'redux-mock-store';
+import fetchMock from 'fetch-mock';
import { ListView } from './ListView';
-const mockedProps = {
+const middlewares = [thunk];
+const mockStore = configureStore(middlewares);
+
+function makeMockLocation(query?: string) {
+ const queryStr = query ? encodeURIComponent(query) : '';
+ return {
+ protocol: 'http:',
+ host: 'localhost',
+ pathname: '/',
+ search: queryStr.length ? `?${queryStr}` : '',
+ } as Location;
+}
+
+const fetchSelectsMock = jest.fn(() => []);
+const mockedPropsComprehensive = {
+ title: 'Data Table',
+ columns: [
+ {
+ accessor: 'id',
+ Header: 'ID',
+ sortable: true,
+ id: 'id',
+ },
+ {
+ accessor: 'age',
+ Header: 'Age',
+ id: 'age',
+ },
+ {
+ accessor: 'name',
+ Header: 'Name',
+ id: 'name',
+ },
+ {
+ accessor: 'time',
+ Header: 'Time',
+ id: 'time',
+ },
+ ],
+ filters: [
+ {
+ key: 'id',
+ Header: 'ID',
+ id: 'id',
+ input: 'select',
+ selects: [{ label: 'foo', value: 'bar' }],
+ operator: 'eq',
+ },
+ {
+ key: 'name',
+ Header: 'Name',
+ id: 'name',
+ input: 'search',
+ operator: 'ct',
+ },
+ {
+ key: 'age',
+ Header: 'Age',
+ id: 'age',
+ input: 'select',
+ fetchSelects: fetchSelectsMock,
+ paginate: true,
+ operator: 'eq',
+ },
+ {
+ key: 'time',
+ Header: 'Time',
+ id: 'time',
+ input: 'datetime_range',
+ operator: 'between',
+ },
+ ],
+ data: [
+ { id: 1, name: 'data 1', age: 10, time: '2020-11-18T07:53:45.354Z' },
+ { id: 2, name: 'data 2', age: 1, time: '2020-11-18T07:53:45.354Z' },
+ ],
+ count: 2,
+ pageSize: 1,
+ fetchData: jest.fn(() => []),
+ loading: false,
+ refreshData: jest.fn(),
+ addSuccessToast: jest.fn(),
+ addDangerToast: jest.fn(),
+ bulkSelectEnabled: true,
+ disableBulkSelect: jest.fn(),
+ bulkActions: [
+ {
+ key: 'something',
+ name: 'do something',
+ style: 'danger',
+ onSelect: jest.fn(),
+ },
+ ],
+ cardSortSelectOptions: [
+ {
+ desc: false,
+ id: 'something',
+ label: 'Alphabetical',
+ value: 'alphabetical',
+ },
+ ],
+};
+
+const mockedPropsSimple = {
title: 'Data Table',
columns: [
{
@@ -59,7 +167,7 @@ const mockedProps = {
test('redirects to first page when page index is invalid', async () => {
const fetchData = jest.fn();
window.history.pushState({}, '', '/?pageIndex=9');
- render(<ListView {...mockedProps} fetchData={fetchData} />, {
+ render(<ListView {...mockedPropsSimple} fetchData={fetchData} />, {
useRouter: true,
useQueryParams: true,
});
@@ -75,3 +183,151 @@ test('redirects to first page when page index is invalid', async () => {
});
fetchData.mockClear();
});
+
+// Comprehensive test suite from original JSX file
+const factory = (props = mockedPropsComprehensive) =>
+ render(
+ <QueryParamProvider location={makeMockLocation()}>
+ <ListView {...(props as any)} />
+ </QueryParamProvider>,
+ { store: mockStore() },
+ );
+
+// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
+describe('ListView', () => {
+ beforeEach(() => {
+ fetchMock.reset();
+ jest.clearAllMocks();
+ factory();
+ });
+
+ afterEach(() => {
+ fetchMock.reset();
+ mockedPropsComprehensive.fetchData.mockClear();
+ mockedPropsComprehensive.bulkActions.forEach(ba => {
+ ba.onSelect.mockClear();
+ });
+ });
+
+ test('calls fetchData on mount', () => {
+ expect(mockedPropsComprehensive.fetchData).toHaveBeenCalledWith({
+ filters: [],
+ pageIndex: 0,
+ pageSize: 1,
+ sortBy: [],
+ });
+ });
+
+ test('calls fetchData on sort', async () => {
+ const sortHeader = screen.getAllByTestId('sort-header')[1];
+ await userEvent.click(sortHeader);
+
+ expect(mockedPropsComprehensive.fetchData).toHaveBeenCalledWith({
+ filters: [],
+ pageIndex: 0,
+ pageSize: 1,
+ sortBy: [
+ {
+ desc: false,
+ id: 'id',
+ },
+ ],
+ });
+ });
+
+ test('renders pagination controls', () => {
+ const paginationList = screen.getByRole('list');
+ expect(paginationList).toBeInTheDocument();
+
+ const pageOneItem = screen.getByRole('listitem', { name: '1' });
+ expect(pageOneItem).toBeInTheDocument();
+ });
+
+ test('calls fetchData on page change', async () => {
+ const pageTwoItem = screen.getByRole('listitem', { name: '2' });
+ await userEvent.click(pageTwoItem);
+
+ await waitFor(() => {
+ const { calls } = mockedPropsComprehensive.fetchData.mock;
+ const pageChangeCall = calls.find(
+ (call: any) =>
+ call?.[0]?.pageIndex === 1 &&
+ call?.[0]?.filters?.length === 0 &&
+ call?.[0]?.pageSize === 1,
+ );
+ expect(pageChangeCall).toBeDefined();
+ });
+ });
+
+ test('handles bulk actions on 1 row', async () => {
+ const checkboxes = screen.getAllByRole('checkbox');
+ await userEvent.click(checkboxes[1]); // Index 1 is the first row checkbox
+
+ const bulkActionButton = within(
+ screen.getByTestId('bulk-select-controls'),
+ ).getByTestId('bulk-select-action');
+ await userEvent.click(bulkActionButton);
+
+ expect(
+ mockedPropsComprehensive.bulkActions[0].onSelect,
+ ).toHaveBeenCalledWith([
+ {
+ age: 10,
+ id: 1,
+ name: 'data 1',
+ time: '2020-11-18T07:53:45.354Z',
+ },
+ ]);
+ });
+
+ test('renders UI filters', () => {
+ const filterControls = screen.getAllByRole('combobox');
+ expect(filterControls).toHaveLength(2);
+ });
+
+ test('calls fetchData on filter', async () => {
+ // Handle select filter
+ const selectFilter = screen.getAllByRole('combobox')[0];
+ await userEvent.click(selectFilter);
+ const option = screen.getByText('foo');
+ await userEvent.click(option);
+
+ // Handle search filter
+ const searchFilter = screen.getByPlaceholderText('Type a value');
+ await userEvent.type(searchFilter, 'something');
+ await userEvent.tab();
+
+ expect(mockedPropsComprehensive.fetchData).toHaveBeenCalledWith(
+ expect.objectContaining({
+ filters: [
+ {
+ id: 'id',
+ operator: 'eq',
+ value: { label: 'foo', value: 'bar' },
+ },
+ {
+ id: 'name',
+ operator: 'ct',
+ value: 'something',
+ },
+ ],
+ }),
+ );
+ });
+
+ test('calls fetchData on card view sort', async () => {
+ factory({
+ ...mockedPropsComprehensive,
+ renderCard: jest.fn(),
+ initialSort: [{ id: 'something' }],
+ } as any);
+
+ const sortSelect = screen.getByTestId('card-sort-select');
+ await userEvent.click(sortSelect);
+
+ const sortOption = screen.getByText('Alphabetical');
+ await userEvent.click(sortOption);
+
+ expect(mockedPropsComprehensive.fetchData).toHaveBeenCalled();
+ });
+});
diff --git a/superset-frontend/src/explore/components/controls/DatasourceControl/DatasourceControl.test.jsx b/superset-frontend/src/explore/components/controls/DatasourceControl/DatasourceControl.test.jsx
deleted file mode 100644
index 8f6b520cab..0000000000
--- a/superset-frontend/src/explore/components/controls/DatasourceControl/DatasourceControl.test.jsx
+++ /dev/null
@@ -1,170 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import configureStore from 'redux-mock-store';
-import { DatasourceType } from '@superset-ui/core';
-import {
- fireEvent,
- render,
- screen,
- userEvent,
- waitFor,
-} from 'spec/helpers/testing-library';
-import DatasourceControl, {
- getDatasourceTitle,
-} from 'src/explore/components/controls/DatasourceControl';
-
-const defaultProps = {
- name: 'datasource',
- label: 'Dataset',
- value: '1__table',
- datasource: {
- name: 'birth_names',
- type: 'table',
- uid: '1__table',
- id: 1,
- columns: [],
- metrics: [],
- owners: [{ username: 'admin', userId: 1 }],
- database: {
- backend: 'mysql',
- name: 'main',
- },
- health_check_message: 'Warning message!',
- },
- actions: {
- setDatasource: jest.fn(),
- },
- onChange: jest.fn(),
- user: {
- createdOn: '2021-04-27T18:12:38.952304',
- email: 'admin',
- firstName: 'admin',
- isActive: true,
- lastName: 'admin',
- permissions: {},
- roles: { Admin: Array(173) },
- userId: 1,
- username: 'admin',
- },
-};
-
-// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
-describe('DatasourceControl', () => {
- const setup = (overrideProps = {}) => {
- const mockStore = configureStore([]);
- const store = mockStore({});
- const props = {
- ...defaultProps,
- ...overrideProps,
- };
- return {
- rendered: render(<DatasourceControl {...props} />, {
- useRedux: true,
- useRouter: true,
- store,
- }),
- store,
- props,
- };
- };
-
- test('should not render Modal', () => {
- setup();
- expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
- });
-
- test('should not render ChangeDatasourceModal', () => {
- setup();
- expect(screen.queryByTestId('Swap dataset-modal')).not.toBeInTheDocument();
- });
-
- test('show or hide Edit Datasource option', async () => {
- const {
- rendered: { container, rerender },
- store,
- props,
- } = setup();
- expect(
- container.querySelector('[data-test="datasource-menu-trigger"]'),
- ).toBeInTheDocument();
- userEvent.click(screen.getByLabelText('more'));
- await waitFor(() => {
- expect(screen.queryAllByRole('menuitem')).toHaveLength(3);
- });
-
- // Close the menu
- userEvent.click(document.body);
- await waitFor(() => {
- expect(screen.queryAllByRole('menuitem')).toHaveLength(0);
- });
-
- rerender(<DatasourceControl {...{ ...props, isEditable: false }} />, {
- useRedux: true,
- useRouter: true,
- store,
- });
- expect(
- container.querySelector('[data-test="datasource-menu-trigger"]'),
- ).toBeInTheDocument();
- userEvent.click(screen.getByLabelText('more'));
- await waitFor(() => {
- expect(screen.queryAllByRole('menuitem')).toHaveLength(2);
- });
- });
-
- test('should render health check message', async () => {
- setup();
- const modalTrigger = screen.getByLabelText('warning');
- expect(modalTrigger).toBeInTheDocument();
-
- // Hover the modal so healthcheck message can show up
- fireEvent.mouseOver(modalTrigger);
- await waitFor(() => {
- expect(
- screen.getByText(defaultProps.datasource.health_check_message),
- ).toBeInTheDocument();
- });
- });
-
- test('Gets Datasource Title', () => {
- const sql = 'This is the sql';
- const name = 'this is a name';
- const emptyResult = '';
- const queryDatasource1 = { type: DatasourceType.Query, sql };
- let displayText = getDatasourceTitle(queryDatasource1);
- expect(displayText).toBe(sql);
- const queryDatasource2 = { type: DatasourceType.Query, sql: null };
- displayText = getDatasourceTitle(queryDatasource2);
- expect(displayText).toBe(null);
- const queryDatasource3 = { type: 'random type', name };
- displayText = getDatasourceTitle(queryDatasource3);
- expect(displayText).toBe(name);
- const queryDatasource4 = { type: 'random type' };
- displayText = getDatasourceTitle(queryDatasource4);
- expect(displayText).toBe(emptyResult);
- displayText = getDatasourceTitle();
- expect(displayText).toBe(emptyResult);
- displayText = getDatasourceTitle(null);
- expect(displayText).toBe(emptyResult);
- displayText = getDatasourceTitle('I should not be a string');
- expect(displayText).toBe(emptyResult);
- displayText = getDatasourceTitle([]);
- expect(displayText).toBe(emptyResult);
- });
-});
diff --git a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.jsx b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.jsx
deleted file mode 100644
index 1b4d43eb9c..0000000000
--- a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.jsx
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import sinon from 'sinon';
-import { getChartMetadataRegistry, ChartMetadata } from '@superset-ui/core';
-import {
- act,
- cleanup,
- render,
- screen,
- userEvent,
-} from 'spec/helpers/testing-library';
-import VizTypeControl from 'src/explore/components/controls/VizTypeControl';
-import { DynamicPluginProvider } from 'src/components';
-
-const defaultProps = {
- name: 'viz_type',
- label: 'Visualization Type',
- value: 'vis1',
- onChange: sinon.spy(),
- isModalOpenInit: true,
-};
-
-/**
- * AntD and/or the Icon component seems to be doing some kind of async changes,
- * so even though the test passes, there is a warning an update to Icon was not
- * wrapped in act(). This sufficiently act-ifies whatever side effects are going
- * on and prevents those warnings.
- */
-const waitForEffects = () =>
- act(() => new Promise(resolve => setTimeout(resolve, 0)));
-
-// Increase global timeout
-jest.setTimeout(60000);
-
-// Add cleanup after each test
-afterEach(async () => {
- cleanup();
- // Wait for any pending effects to complete
- await new Promise(resolve => setTimeout(resolve, 0));
-});
-
-// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
-describe('VizTypeControl', () => {
- const registry = getChartMetadataRegistry();
- registry
- .registerValue(
- 'vis1',
- new ChartMetadata({
- name: 'vis1',
- thumbnail: '',
- tags: ['Featured'],
- }),
- )
- .registerValue(
- 'vis2',
- new ChartMetadata({
- name: 'vis2',
- thumbnail: '',
- tags: ['foobar'],
- }),
- );
-
- beforeEach(async () => {
- render(
- <DynamicPluginProvider>
- <VizTypeControl {...defaultProps} />
- </DynamicPluginProvider>,
- { useRedux: true },
- );
- await waitForEffects();
- }, 30000); // Increase beforeEach timeout
-
- test('calls onChange when submitted', async () => {
- const thumbnail = await screen.findByTestId('viztype-selector-container', {
- timeout: 15000,
- });
- const submit = await screen.findByText('Select', { timeout: 15000 });
-
- await act(async () => {
- userEvent.click(thumbnail);
- await waitForEffects();
- });
-
- expect(defaultProps.onChange.called).toBe(false);
-
- await act(async () => {
- userEvent.click(submit);
- await waitForEffects();
- });
-
- expect(defaultProps.onChange.called).toBe(true);
- }, 30000);
-
- test('filters images based on text input', async () => {
- const thumbnails = await screen.findByTestId('viztype-selector-container', {
- timeout: 15000,
- });
- expect(thumbnails).toBeInTheDocument();
-
- const searchInput = await screen.findByPlaceholderText(
- 'Search all charts',
- { timeout: 15000 },
- );
-
- await act(async () => {
- userEvent.type(searchInput, 'foo');
- await waitForEffects();
- });
-
- const thumbnail = await screen.findByTestId('viztype-selector-container', {
- timeout: 15000,
- });
- expect(thumbnail).toBeInTheDocument();
- }, 30000);
-});