mirror of
https://github.com/apache/superset.git
synced 2026-04-19 16:14:52 +00:00
test(chart-list): migrate Chart List tests from Cypress to RTL (#37813)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,57 +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 { CHART_LIST } from 'cypress/utils/urls';
|
||||
import { setGridMode, clearAllInputs } from 'cypress/utils';
|
||||
import { setFilter } from '../explore/utils';
|
||||
|
||||
describe('Charts filters', () => {
|
||||
before(() => {
|
||||
cy.visit(CHART_LIST);
|
||||
setGridMode('card');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
clearAllInputs();
|
||||
});
|
||||
|
||||
it('should allow filtering by "Owner"', () => {
|
||||
setFilter('Owner', 'alpha user');
|
||||
setFilter('Owner', 'admin user');
|
||||
});
|
||||
|
||||
it('should allow filtering by "Modified by" correctly', () => {
|
||||
setFilter('Modified by', 'alpha user');
|
||||
setFilter('Modified by', 'admin user');
|
||||
});
|
||||
|
||||
it('should allow filtering by "Type" correctly', () => {
|
||||
setFilter('Type', 'Area Chart');
|
||||
setFilter('Type', 'Bubble Chart');
|
||||
});
|
||||
|
||||
it('should allow filtering by "Dataset" correctly', () => {
|
||||
setFilter('Dataset', 'birth_names');
|
||||
setFilter('Dataset', 'video_game_sales');
|
||||
});
|
||||
|
||||
it('should allow filtering by "Dashboards" correctly', () => {
|
||||
setFilter('Dashboard', 'USA Births Names');
|
||||
setFilter('Dashboard', 'Video Game Sales');
|
||||
});
|
||||
});
|
||||
@@ -23,12 +23,9 @@ import {
|
||||
interceptBulkDelete,
|
||||
interceptUpdate,
|
||||
interceptDelete,
|
||||
visitSampleChartFromList,
|
||||
saveChartToDashboard,
|
||||
interceptFiltering,
|
||||
interceptFavoriteStatus,
|
||||
} from '../explore/utils';
|
||||
import { interceptGet as interceptDashboardGet } from '../dashboard/utils';
|
||||
|
||||
function orderAlphabetical() {
|
||||
setFilter('Sort', 'Alphabetical');
|
||||
@@ -57,60 +54,6 @@ function visitChartList() {
|
||||
}
|
||||
|
||||
describe('Charts list', () => {
|
||||
describe('Cross-referenced dashboards', () => {
|
||||
beforeEach(() => {
|
||||
cy.createSampleDashboards([0, 1, 2, 3]);
|
||||
cy.createSampleCharts([0]);
|
||||
visitChartList();
|
||||
});
|
||||
|
||||
// Skipped: depends on "Supported Charts Dashboard" which requires specific example loading
|
||||
it.skip('should show the cross-referenced dashboards in the table cell', () => {
|
||||
interceptDashboardGet();
|
||||
cy.getBySel('table-row')
|
||||
.first()
|
||||
.find('[data-test="table-row-cell"]')
|
||||
.find('[data-test="crosslinks"]')
|
||||
.should('be.empty');
|
||||
cy.getBySel('table-row')
|
||||
.eq(10)
|
||||
.find('[data-test="table-row-cell"]')
|
||||
.find('[data-test="crosslinks"]')
|
||||
.contains('Supported Charts Dashboard')
|
||||
.invoke('removeAttr', 'target')
|
||||
.click();
|
||||
cy.wait('@get');
|
||||
});
|
||||
|
||||
it('should show the newly added dashboards in a tooltip', () => {
|
||||
interceptDashboardGet();
|
||||
visitSampleChartFromList('1 - Sample chart');
|
||||
saveChartToDashboard('1 - Sample chart', '1 - Sample dashboard');
|
||||
saveChartToDashboard('1 - Sample chart', '2 - Sample dashboard');
|
||||
saveChartToDashboard('1 - Sample chart', '3 - Sample dashboard');
|
||||
saveChartToDashboard('1 - Sample chart', '4 - Sample dashboard');
|
||||
visitChartList();
|
||||
|
||||
cy.getBySel('count-crosslinks').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
describe('card mode', () => {
|
||||
before(() => {
|
||||
visitChartList();
|
||||
setGridMode('card');
|
||||
});
|
||||
|
||||
it('should preserve other filters when sorting', () => {
|
||||
// Check that we have some cards (count varies based on loaded examples)
|
||||
cy.getBySel('styled-card').should('have.length.at.least', 1);
|
||||
setFilter('Type', 'Big Number');
|
||||
setFilter('Sort', 'Least recently modified');
|
||||
// After filtering to Big Number type, we should have fewer cards
|
||||
cy.getBySel('styled-card').should('have.length.at.least', 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('common actions', () => {
|
||||
beforeEach(() => {
|
||||
visitChartList();
|
||||
|
||||
@@ -17,7 +17,12 @@
|
||||
* under the License.
|
||||
*/
|
||||
import fetchMock from 'fetch-mock';
|
||||
import { fireEvent, screen, waitFor } from 'spec/helpers/testing-library';
|
||||
import {
|
||||
fireEvent,
|
||||
screen,
|
||||
waitFor,
|
||||
within,
|
||||
} from 'spec/helpers/testing-library';
|
||||
import { isFeatureEnabled } from '@superset-ui/core';
|
||||
import {
|
||||
mockCharts,
|
||||
@@ -475,10 +480,11 @@ describe('ChartList Card View Tests', () => {
|
||||
expect(screen.getByTestId('bulk-select-controls')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Click the X button to close bulk select (look for close icon in bulk select bar)
|
||||
const closeButton = document.querySelector(
|
||||
'.ant-alert-close-icon',
|
||||
) as HTMLButtonElement;
|
||||
// Click the X button to close bulk select
|
||||
const bulkSelectBar = screen.getByTestId('bulk-select-controls');
|
||||
const closeButton = within(bulkSelectBar).getByRole('button', {
|
||||
name: /close/i,
|
||||
});
|
||||
fireEvent.click(closeButton);
|
||||
|
||||
// Verify bulk select controls are gone
|
||||
@@ -489,35 +495,6 @@ describe('ChartList Card View Tests', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('exit bulk select by clicking bulk select button again', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
// Wait for cards to load
|
||||
await screen.findByTestId('chart-list-view');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(mockCharts[0].slice_name)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Enable bulk select mode
|
||||
const bulkSelectButton = screen.getByTestId('bulk-select');
|
||||
fireEvent.click(bulkSelectButton);
|
||||
|
||||
// Wait for bulk select controls
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('bulk-select-controls')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Click bulk select button again to exit
|
||||
fireEvent.click(bulkSelectButton);
|
||||
|
||||
// Verify bulk select controls are gone
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.queryByTestId('bulk-select-controls'),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
test('card click behavior changes in bulk select mode', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ afterEach(() => {
|
||||
mockIsFeatureEnabled.mockReset();
|
||||
});
|
||||
|
||||
test('ChartList list view renders correctly', async () => {
|
||||
test('renders table in list view', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
// Wait for component to load
|
||||
@@ -86,12 +86,10 @@ test('ChartList list view renders correctly', async () => {
|
||||
});
|
||||
|
||||
// Verify cards are not rendered in list view
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId('styled-card')).not.toBeInTheDocument();
|
||||
});
|
||||
expect(screen.queryByTestId('styled-card')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('ChartList list view correctly displays dataset names with and without schema', async () => {
|
||||
test('displays dataset names with and without schema prefix', async () => {
|
||||
// Create custom mock data with different datasource_name_text formats
|
||||
const customMockCharts = [
|
||||
{
|
||||
@@ -167,7 +165,7 @@ test('ChartList list view correctly displays dataset names with and without sche
|
||||
expect(dotsLink).toHaveTextContent('table.with.dots');
|
||||
});
|
||||
|
||||
test('ChartList list view switches from list view to card view', async () => {
|
||||
test('switches from list view to card view', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -188,7 +186,7 @@ test('ChartList list view switches from list view to card view', async () => {
|
||||
expect(cards).toHaveLength(mockCharts.length);
|
||||
});
|
||||
|
||||
test('ChartList list view renders all required column headers', async () => {
|
||||
test('renders all required column headers', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -218,7 +216,7 @@ test('ChartList list view renders all required column headers', async () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('ChartList list view sorts table when clicking column headers', async () => {
|
||||
test('sorts table when clicking column headers', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -235,7 +233,7 @@ test('ChartList list view sorts table when clicking column headers', async () =>
|
||||
expect(sortableHeaders).toHaveLength(3);
|
||||
|
||||
const nameHeader = within(table).getByTitle('Name');
|
||||
userEvent.click(nameHeader);
|
||||
await userEvent.click(nameHeader);
|
||||
|
||||
await waitFor(() => {
|
||||
const sortCalls = fetchMock.callHistory
|
||||
@@ -248,7 +246,7 @@ test('ChartList list view sorts table when clicking column headers', async () =>
|
||||
});
|
||||
|
||||
const typeHeader = within(table).getByTitle('Type');
|
||||
userEvent.click(typeHeader);
|
||||
await userEvent.click(typeHeader);
|
||||
|
||||
await waitFor(() => {
|
||||
const typeSortCalls = fetchMock.callHistory
|
||||
@@ -261,7 +259,7 @@ test('ChartList list view sorts table when clicking column headers', async () =>
|
||||
});
|
||||
|
||||
const lastModifiedHeader = within(table).getByTitle('Last modified');
|
||||
userEvent.click(lastModifiedHeader);
|
||||
await userEvent.click(lastModifiedHeader);
|
||||
|
||||
await waitFor(() => {
|
||||
const lastModifiedSortCalls = fetchMock.callHistory
|
||||
@@ -275,7 +273,7 @@ test('ChartList list view sorts table when clicking column headers', async () =>
|
||||
});
|
||||
});
|
||||
|
||||
test('ChartList list view displays chart data correctly', async () => {
|
||||
test('displays chart data correctly in table rows', async () => {
|
||||
/**
|
||||
* @todo Implement test logic for tagging.
|
||||
* If TAGGING_SYSTEM is ever deprecated to always be on,
|
||||
@@ -354,7 +352,7 @@ test('ChartList list view displays chart data correctly', async () => {
|
||||
expect(within(chartRow).getByTestId('edit-alt')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('ChartList list view export chart api called when export button is clicked', async () => {
|
||||
test('calls export API when export button is clicked', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -381,7 +379,7 @@ test('ChartList list view export chart api called when export button is clicked'
|
||||
});
|
||||
});
|
||||
|
||||
test('ChartList list view opens edit properties modal when edit button is clicked', async () => {
|
||||
test('opens edit properties modal on edit button click', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -405,7 +403,7 @@ test('ChartList list view opens edit properties modal when edit button is clicke
|
||||
});
|
||||
});
|
||||
|
||||
test('ChartList list view opens delete confirmation when delete button is clicked', async () => {
|
||||
test('opens delete confirmation on delete button click', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -429,7 +427,7 @@ test('ChartList list view opens delete confirmation when delete button is clicke
|
||||
});
|
||||
});
|
||||
|
||||
test('ChartList list view displays certified badge only for certified charts', async () => {
|
||||
test('displays certified badge only for certified charts', async () => {
|
||||
// Test certified chart (mockCharts[1] has certification)
|
||||
const certifiedChart = mockCharts[1];
|
||||
// Test uncertified chart (mockCharts[0] has no certification)
|
||||
@@ -468,7 +466,7 @@ test('ChartList list view displays certified badge only for certified charts', a
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('ChartList list view displays info icon only for charts with descriptions', async () => {
|
||||
test('displays info icon only for charts with descriptions', async () => {
|
||||
// Test chart with description (mockCharts[0] has description)
|
||||
const chartWithDesc = mockCharts[0];
|
||||
// Test chart without description (mockCharts[2] has description: null)
|
||||
@@ -506,47 +504,7 @@ test('ChartList list view displays info icon only for charts with descriptions',
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('ChartList list view displays chart with empty dataset column', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('listview-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(mockCharts[2].slice_name)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const table = screen.getByTestId('listview-table');
|
||||
const chartNameElement = within(table).getByText(mockCharts[2].slice_name);
|
||||
const chartRow = chartNameElement.closest(
|
||||
'[data-test="table-row"]',
|
||||
) as HTMLElement;
|
||||
|
||||
// Chart name should be visible
|
||||
expect(
|
||||
within(chartRow).getByText(mockCharts[2].slice_name),
|
||||
).toBeInTheDocument();
|
||||
|
||||
// Find dataset column index by header
|
||||
const headers = within(table).getAllByRole('columnheader');
|
||||
const datasetHeaderIndex = headers.findIndex(header =>
|
||||
header.textContent?.includes('Dataset'),
|
||||
);
|
||||
expect(datasetHeaderIndex).toBeGreaterThan(-1); // Ensure column exists
|
||||
|
||||
// Since mockCharts[2] has datasource_name_text: null, verify dataset cell is empty
|
||||
const datasetCell = within(chartRow).getAllByRole('cell')[datasetHeaderIndex];
|
||||
expect(datasetCell).toBeInTheDocument();
|
||||
|
||||
// Verify dataset cell is empty for charts with no dataset
|
||||
expect(datasetCell).toHaveTextContent('');
|
||||
// There's a link element but with empty href
|
||||
const datasetLink = within(datasetCell).getByRole('link');
|
||||
expect(datasetLink).toHaveAttribute('href', '');
|
||||
});
|
||||
|
||||
test('ChartList list view displays chart with empty on dashboards column', async () => {
|
||||
test('renders empty dashboard column for charts without dashboards', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -585,7 +543,35 @@ test('ChartList list view displays chart with empty on dashboards column', async
|
||||
expect(within(dashboardCell).queryByRole('link')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('ChartList list view shows tag info when TAGGING_SYSTEM is enabled', async () => {
|
||||
test('renders dashboard crosslinks as navigable links', async () => {
|
||||
renderChartList(mockUser);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('listview-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const table = screen.getByTestId('listview-table');
|
||||
|
||||
// mockCharts[1] has multiple dashboards - verify all render with correct hrefs
|
||||
const chartRow = within(table)
|
||||
.getByText(mockCharts[1].slice_name)
|
||||
.closest('[data-test="table-row"]') as HTMLElement;
|
||||
const crosslinks = within(chartRow).getByTestId('crosslinks');
|
||||
const dashboards = mockCharts[1].dashboards as {
|
||||
dashboard_title: string;
|
||||
id: number;
|
||||
}[];
|
||||
const links = within(crosslinks).getAllByRole('link');
|
||||
expect(links).toHaveLength(dashboards.length);
|
||||
dashboards.forEach(dashboard => {
|
||||
expect(
|
||||
within(crosslinks).getByRole('link', {
|
||||
name: new RegExp(dashboard.dashboard_title),
|
||||
}),
|
||||
).toHaveAttribute('href', `/superset/dashboard/${dashboard.id}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('shows tag column when TAGGING_SYSTEM is enabled', async () => {
|
||||
// Enable tagging system feature flag
|
||||
mockIsFeatureEnabled.mockImplementation(
|
||||
feature => feature === 'TAGGING_SYSTEM',
|
||||
@@ -625,7 +611,7 @@ test('ChartList list view shows tag info when TAGGING_SYSTEM is enabled', async
|
||||
expect(tagLink).toHaveAttribute('target', '_blank');
|
||||
});
|
||||
|
||||
test('ChartList list view can bulk select and deselect all charts', async () => {
|
||||
test('supports bulk select and deselect all', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -685,7 +671,7 @@ test('ChartList list view can bulk select and deselect all charts', async () =>
|
||||
expect(screen.queryByTestId('bulk-select-action')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('ChartList list view can bulk export selected charts', async () => {
|
||||
test('supports bulk export of selected charts', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -731,7 +717,7 @@ test('ChartList list view can bulk export selected charts', async () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('ChartList list view can bulk delete selected charts', async () => {
|
||||
test('supports bulk delete of selected charts', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -777,7 +763,7 @@ test('ChartList list view can bulk delete selected charts', async () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('ChartList list view can bulk add tags to selected charts', async () => {
|
||||
test('supports bulk add tags to selected charts', async () => {
|
||||
// Enable tagging system feature flag
|
||||
mockIsFeatureEnabled.mockImplementation(
|
||||
feature => feature === 'TAGGING_SYSTEM',
|
||||
@@ -828,51 +814,7 @@ test('ChartList list view can bulk add tags to selected charts', async () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('ChartList list view exit bulk select by hitting x on bulk select bar', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('listview-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(mockCharts[0].slice_name)).toBeInTheDocument();
|
||||
expect(screen.getByText(mockCharts[1].slice_name)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const bulkSelectButton = screen.getByTestId('bulk-select');
|
||||
await userEvent.click(bulkSelectButton);
|
||||
|
||||
await waitFor(() => {
|
||||
// Expect header checkbox + one checkbox per chart
|
||||
expect(screen.getAllByRole('checkbox')).toHaveLength(mockCharts.length + 1);
|
||||
});
|
||||
|
||||
const table = screen.getByTestId('listview-table');
|
||||
// Target first data row specifically (not header row)
|
||||
const dataRows = within(table).getAllByTestId('table-row');
|
||||
const firstRowCheckbox = within(dataRows[0]).getByRole('checkbox');
|
||||
await userEvent.click(firstRowCheckbox);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('bulk-select-copy')).toHaveTextContent(
|
||||
'1 Selected',
|
||||
);
|
||||
});
|
||||
|
||||
// Find and click the close button (x) on the bulk select bar
|
||||
const closeIcon = document.querySelector(
|
||||
'.ant-alert-close-icon',
|
||||
) as HTMLButtonElement;
|
||||
await userEvent.click(closeIcon);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryAllByRole('checkbox')).toHaveLength(0);
|
||||
expect(screen.queryByTestId('bulk-select-copy')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
test('ChartList list view exit bulk select by clicking bulk select button again', async () => {
|
||||
test('exits bulk select on button toggle', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -911,34 +853,3 @@ test('ChartList list view exit bulk select by clicking bulk select button again'
|
||||
expect(screen.queryByTestId('bulk-select-copy')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
test('ChartList list view displays dataset name without schema prefix correctly', async () => {
|
||||
// Test just name case - should display the full name when no schema prefix
|
||||
renderChartList(mockUser);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('listview-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const table = screen.getByTestId('listview-table');
|
||||
|
||||
// Wait for chart with simple dataset name to load
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
within(table).getByText(mockCharts[1].slice_name),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Test mockCharts[1] which has 'sales_data' (no schema prefix)
|
||||
const chart1Row = within(table)
|
||||
.getByText(mockCharts[1].slice_name)
|
||||
.closest('[data-test="table-row"]') as HTMLElement;
|
||||
const chart1DatasetLink = within(chart1Row).getByTestId('internal-link');
|
||||
|
||||
// Should display the full name when there's no schema prefix
|
||||
expect(chart1DatasetLink).toHaveTextContent('sales_data');
|
||||
expect(chart1DatasetLink).toHaveAttribute(
|
||||
'href',
|
||||
mockCharts[1].datasource_url,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -87,7 +87,7 @@ describe('ChartList', () => {
|
||||
expect(screen.getByText('Charts')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('verify New Chart button existence and functionality', async () => {
|
||||
test('navigates to /chart/add on New Chart button click', async () => {
|
||||
renderChartList(mockUser);
|
||||
await screen.findByTestId('chart-list-view');
|
||||
|
||||
@@ -108,7 +108,7 @@ describe('ChartList', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('verify Import button existence and functionality', async () => {
|
||||
test('opens import modal on Import button click', async () => {
|
||||
renderChartList(mockUser);
|
||||
await screen.findByTestId('chart-list-view');
|
||||
|
||||
@@ -168,72 +168,6 @@ describe('ChartList', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('shows loading state while API calls are in progress', async () => {
|
||||
// Mock delayed API responses
|
||||
// fetchMock.removeRoute(API_ENDPOINTS.CHARTS_INFO)
|
||||
fetchMock.removeRoutes();
|
||||
fetchMock.get(
|
||||
API_ENDPOINTS.CHARTS_INFO,
|
||||
new Promise(resolve =>
|
||||
setTimeout(
|
||||
() => resolve({ permissions: ['can_read', 'can_write'] }),
|
||||
100,
|
||||
),
|
||||
),
|
||||
{ name: API_ENDPOINTS.CHARTS_INFO },
|
||||
);
|
||||
|
||||
// fetchMock.removeRoute(API_ENDPOINTS.CHARTS)
|
||||
fetchMock.get(
|
||||
API_ENDPOINTS.CHARTS,
|
||||
new Promise(resolve =>
|
||||
setTimeout(() => resolve({ result: mockCharts, chart_count: 3 }), 150),
|
||||
),
|
||||
{ name: API_ENDPOINTS.CHARTS },
|
||||
);
|
||||
|
||||
renderChartList(mockUser);
|
||||
|
||||
// Main container should render immediately
|
||||
expect(screen.getByTestId('chart-list-view')).toBeInTheDocument();
|
||||
|
||||
// Eventually data should load
|
||||
await waitFor(
|
||||
() => {
|
||||
const infoCalls = fetchMock.callHistory.calls(/chart\/_info/);
|
||||
const dataCalls = fetchMock.callHistory.calls(/chart\/\?q/);
|
||||
|
||||
expect(infoCalls).toHaveLength(1);
|
||||
expect(dataCalls).toHaveLength(1);
|
||||
},
|
||||
{ timeout: 1000 },
|
||||
);
|
||||
});
|
||||
|
||||
test('maintains component structure during loading', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
// Core structure should be available immediately
|
||||
expect(screen.getByTestId('chart-list-view')).toBeInTheDocument();
|
||||
expect(screen.getByText('Charts')).toBeInTheDocument();
|
||||
|
||||
// View toggles should be available during loading
|
||||
expect(screen.getByRole('img', { name: 'appstore' })).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('img', { name: 'unordered-list' }),
|
||||
).toBeInTheDocument();
|
||||
|
||||
// Wait for permissions to load, then action buttons should appear
|
||||
expect(
|
||||
await screen.findByRole('button', { name: 'Bulk select' }),
|
||||
).toBeInTheDocument();
|
||||
|
||||
// Wait for data to eventually load
|
||||
expect(
|
||||
await screen.findByText(mockCharts[0].slice_name),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('displays Matrixify tag for charts with matrixify enabled', async () => {
|
||||
renderChartList(mockUser);
|
||||
|
||||
@@ -278,7 +212,7 @@ describe('ChartList', () => {
|
||||
expect(screen.getByTestId('chart-list-view')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('handles empty results', async () => {
|
||||
test('renders controls when chart list is empty', async () => {
|
||||
// Mock empty chart data (not permissions)
|
||||
fetchMock.removeRoute(API_ENDPOINTS.CHARTS);
|
||||
fetchMock.get(
|
||||
@@ -319,107 +253,32 @@ describe('ChartList - Global Filter Interactions', () => {
|
||||
).mockReset();
|
||||
});
|
||||
|
||||
test('renders search filter correctly', async () => {
|
||||
test('renders all standard filters', async () => {
|
||||
renderChartList(mockUser);
|
||||
await screen.findByTestId('chart-list-view');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('listview-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Verify search filter renders correctly
|
||||
// Search filter
|
||||
expect(screen.getByTestId('filters-search')).toBeInTheDocument();
|
||||
expect(screen.getByPlaceholderText(/type a value/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('renders Type filter correctly', async () => {
|
||||
renderChartList(mockUser);
|
||||
await screen.findByTestId('chart-list-view');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('listview-table')).toBeInTheDocument();
|
||||
// All standard select filters
|
||||
const standardFilters = [
|
||||
'Type',
|
||||
'Dataset',
|
||||
'Owner',
|
||||
'Certified',
|
||||
'Favorite',
|
||||
'Dashboard',
|
||||
'Modified by',
|
||||
];
|
||||
standardFilters.forEach(filterLabel => {
|
||||
const filter = findFilterByLabel(filterLabel);
|
||||
expect(filter).toBeVisible();
|
||||
expect(filter).toBeEnabled();
|
||||
});
|
||||
|
||||
const typeFilter = findFilterByLabel('Type');
|
||||
expect(typeFilter).toBeVisible();
|
||||
expect(typeFilter).toBeEnabled();
|
||||
});
|
||||
|
||||
test('renders Dataset filter correctly', async () => {
|
||||
renderChartList(mockUser);
|
||||
await screen.findByTestId('chart-list-view');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('listview-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const datasetFilter = findFilterByLabel('Dataset');
|
||||
expect(datasetFilter).toBeVisible();
|
||||
expect(datasetFilter).toBeEnabled();
|
||||
});
|
||||
|
||||
test('renders Owner filter correctly', async () => {
|
||||
renderChartList(mockUser);
|
||||
await screen.findByTestId('chart-list-view');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('listview-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const ownerFilter = findFilterByLabel('Owner');
|
||||
expect(ownerFilter).toBeVisible();
|
||||
expect(ownerFilter).toBeEnabled();
|
||||
});
|
||||
|
||||
test('renders Certified filter correctly', async () => {
|
||||
renderChartList(mockUser);
|
||||
await screen.findByTestId('chart-list-view');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('listview-table')).toBeInTheDocument();
|
||||
});
|
||||
const certifiedFilter = findFilterByLabel('Certified');
|
||||
expect(certifiedFilter).toBeVisible();
|
||||
expect(certifiedFilter).toBeEnabled();
|
||||
});
|
||||
|
||||
test('renders Favorite filter correctly', async () => {
|
||||
renderChartList(mockUser);
|
||||
await screen.findByTestId('chart-list-view');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('listview-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const favoriteFilter = findFilterByLabel('Favorite');
|
||||
expect(favoriteFilter).toBeVisible();
|
||||
expect(favoriteFilter).toBeEnabled();
|
||||
});
|
||||
|
||||
test('renders Dashboard filter correctly', async () => {
|
||||
renderChartList(mockUser);
|
||||
await screen.findByTestId('chart-list-view');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('listview-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const dashboardFilter = findFilterByLabel('Dashboard');
|
||||
expect(dashboardFilter).toBeVisible();
|
||||
expect(dashboardFilter).toBeEnabled();
|
||||
});
|
||||
|
||||
test('renders Modified by filter correctly', async () => {
|
||||
renderChartList(mockUser);
|
||||
await screen.findByTestId('chart-list-view');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('listview-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const modifiedByFilter = findFilterByLabel('Modified by');
|
||||
expect(modifiedByFilter).toBeVisible();
|
||||
expect(modifiedByFilter).toBeEnabled();
|
||||
});
|
||||
|
||||
test('renders Tags filter when TAGGING_SYSTEM is enabled', async () => {
|
||||
@@ -476,7 +335,7 @@ describe('ChartList - Global Filter Interactions', () => {
|
||||
expect(filterLabels).not.toContain('Tag');
|
||||
});
|
||||
|
||||
test('allows filters to be reset correctly', async () => {
|
||||
test('resets search filter value on clear', async () => {
|
||||
renderChartList(mockUser);
|
||||
await screen.findByTestId('chart-list-view');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user