From 60046ca1ccd99a2c2b80e500289dc9762556c3a5 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Fri, 28 Apr 2023 17:33:45 +0200 Subject: [PATCH] chore: Add Cypress tests for drill by (#23849) --- .../cypress/e2e/dashboard/drillby.test.ts | 705 ++++++++++++++++++ .../e2e/dashboard/drilltodetail.test.ts | 14 +- .../cypress/e2e/dashboard/utils.ts | 18 + .../cypress-base/cypress/e2e/explore/utils.ts | 14 +- .../components/Chart/DrillBy/DrillByChart.tsx | 1 + .../Chart/DrillBy/useDisplayModeToggle.tsx | 1 + .../Chart/DrillBy/useResultsTableView.tsx | 4 +- .../examples/supported_charts_dashboard.py | 2 +- .../integration_tests/superset_test_config.py | 3 +- 9 files changed, 746 insertions(+), 16 deletions(-) create mode 100644 superset-frontend/cypress-base/cypress/e2e/dashboard/drillby.test.ts diff --git a/superset-frontend/cypress-base/cypress/e2e/dashboard/drillby.test.ts b/superset-frontend/cypress-base/cypress/e2e/dashboard/drillby.test.ts new file mode 100644 index 000000000..c365f66b4 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/e2e/dashboard/drillby.test.ts @@ -0,0 +1,705 @@ +/** + * 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. + */ +// eslint-disable-next-line import/no-extraneous-dependencies +import { Interception } from 'cypress/types/net-stubbing'; +import { waitForChartLoad } from 'cypress/utils'; +import { SUPPORTED_CHARTS_DASHBOARD } from 'cypress/utils/urls'; +import { + openTopLevelTab, + SUPPORTED_TIER1_CHARTS, + SUPPORTED_TIER2_CHARTS, +} from './utils'; +import { + interceptExploreJson, + interceptV1ChartData, + interceptFormDataKey, +} from '../explore/utils'; + +const closeModal = () => { + cy.get('body').then($body => { + if ($body.find('[data-test="close-drill-by-modal"]').length) { + cy.getBySel('close-drill-by-modal').click({ force: true }); + } + }); +}; + +const openTableContextMenu = ( + cellContent: string, + tableSelector = "[data-test-viz-type='table']", +) => { + cy.get(tableSelector) + .scrollIntoView() + .contains(cellContent) + .first() + .rightclick(); +}; + +const drillBy = (targetDrillByColumn: string, isLegacy = false) => { + if (isLegacy) { + interceptExploreJson('legacyData'); + } else { + interceptV1ChartData(); + } + + cy.get('.ant-dropdown:not(.ant-dropdown-hidden)') + .first() + .find("[role='menu'] [role='menuitem'] [title='Drill by']") + .trigger('mouseover'); + cy.get( + '.ant-dropdown-menu-submenu:not(.ant-dropdown-menu-hidden) [data-test="drill-by-submenu"]', + ) + .find('[role="menuitem"]') + .contains(new RegExp(`^${targetDrillByColumn}$`)) + .first() + .click({ force: true }); + + if (isLegacy) { + return cy.wait('@legacyData'); + } + return cy.wait('@v1Data'); +}; + +const verifyExpectedFormData = ( + interceptedRequest: Interception, + expectedFormData: Record, +) => { + const actualFormData = interceptedRequest.request.body?.form_data; + Object.entries(expectedFormData).forEach(([key, val]) => { + expect(actualFormData?.[key]).to.eql(val); + }); +}; + +const testEchart = ( + vizType: string, + chartName: string, + drillClickCoordinates: [[number, number], [number, number]], + furtherDrillDimension = 'name', +) => { + cy.get(`[data-test-viz-type='${vizType}'] canvas`).then($canvas => { + // click 'boy' + cy.wrap($canvas) + .scrollIntoView() + .trigger( + 'mouseover', + drillClickCoordinates[0][0], + drillClickCoordinates[0][1], + ) + .rightclick(drillClickCoordinates[0][0], drillClickCoordinates[0][1]); + + drillBy('state').then(intercepted => { + verifyExpectedFormData(intercepted, { + groupby: ['state'], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: 'boy', + expressionType: 'SIMPLE', + operator: '==', + operatorId: 'EQUALS', + subject: 'gender', + }, + ], + }); + }); + + cy.getBySel(`"Drill by: ${chartName}-modal"`).as('drillByModal'); + + cy.get('@drillByModal') + .find('.draggable-trigger') + .should('contain', chartName); + + cy.get('@drillByModal') + .find('.ant-breadcrumb') + .should('be.visible') + .and('contain', 'gender (boy)') + .and('contain', '/') + .and('contain', 'state'); + + cy.get('@drillByModal') + .find('[data-test="drill-by-chart"]') + .should('be.visible'); + + // further drill + cy.get(`[data-test="drill-by-chart"] canvas`).then($canvas => { + // click 'other' + cy.wrap($canvas) + .scrollIntoView() + .trigger( + 'mouseover', + drillClickCoordinates[1][0], + drillClickCoordinates[1][1], + ) + .rightclick(drillClickCoordinates[1][0], drillClickCoordinates[1][1]); + + drillBy(furtherDrillDimension).then(intercepted => { + verifyExpectedFormData(intercepted, { + groupby: [furtherDrillDimension], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: 'boy', + expressionType: 'SIMPLE', + operator: '==', + operatorId: 'EQUALS', + subject: 'gender', + }, + { + clause: 'WHERE', + comparator: 'other', + expressionType: 'SIMPLE', + operator: '==', + operatorId: 'EQUALS', + subject: 'state', + }, + ], + }); + }); + + cy.get('@drillByModal') + .find('[data-test="drill-by-chart"]') + .should('be.visible'); + + // undo - back to drill by state + interceptV1ChartData('drillByUndo'); + cy.get('@drillByModal') + .find('.ant-breadcrumb') + .should('be.visible') + .and('contain', 'gender (boy)') + .and('contain', '/') + .and('contain', 'state (other)') + .and('contain', furtherDrillDimension) + .contains('state (other)') + .click(); + cy.wait('@drillByUndo').then(intercepted => { + verifyExpectedFormData(intercepted, { + groupby: ['state'], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: 'boy', + expressionType: 'SIMPLE', + operator: '==', + operatorId: 'EQUALS', + subject: 'gender', + }, + ], + }); + }); + + cy.get('@drillByModal') + .find('.ant-breadcrumb') + .should('be.visible') + .and('contain', 'gender (boy)') + .and('contain', '/') + .and('not.contain', 'state (other)') + .and('not.contain', furtherDrillDimension) + .and('contain', 'state'); + + cy.get('@drillByModal') + .find('[data-test="drill-by-chart"]') + .should('be.visible'); + }); + }); +}; + +describe('Drill by modal', () => { + beforeEach(() => { + closeModal(); + }); + before(() => { + cy.visit(SUPPORTED_CHARTS_DASHBOARD); + }); + + describe('Modal actions + Table', () => { + before(() => { + closeModal(); + openTopLevelTab('Tier 1'); + SUPPORTED_TIER1_CHARTS.forEach(waitForChartLoad); + }); + + it('opens the modal from the context menu', () => { + openTableContextMenu('boy'); + drillBy('state').then(intercepted => { + verifyExpectedFormData(intercepted, { + groupby: ['state'], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: 'boy', + expressionType: 'SIMPLE', + operator: '==', + operatorId: 'EQUALS', + subject: 'gender', + }, + ], + }); + }); + + cy.getBySel('"Drill by: Table-modal"').as('drillByModal'); + + cy.get('@drillByModal') + .find('.draggable-trigger') + .should('contain', 'Drill by: Table'); + + cy.get('@drillByModal') + .find('[data-test="metadata-bar"]') + .should('be.visible'); + + cy.get('@drillByModal') + .find('.ant-breadcrumb') + .should('be.visible') + .and('contain', 'gender (boy)') + .and('contain', '/') + .and('contain', 'state'); + + cy.get('@drillByModal') + .find('[data-test="drill-by-chart"]') + .should('be.visible') + .and('contain', 'state') + .and('contain', 'sum__num'); + + // further drilling + openTableContextMenu('CA', '[data-test="drill-by-chart"]'); + drillBy('name').then(intercepted => { + verifyExpectedFormData(intercepted, { + groupby: ['name'], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: 'boy', + expressionType: 'SIMPLE', + operator: '==', + operatorId: 'EQUALS', + subject: 'gender', + }, + { + clause: 'WHERE', + comparator: 'CA', + expressionType: 'SIMPLE', + operator: '==', + operatorId: 'EQUALS', + subject: 'state', + }, + ], + }); + }); + + cy.get('@drillByModal') + .find('[data-test="drill-by-chart"]') + .should('be.visible') + .and('not.contain', 'state') + .and('contain', 'name') + .and('contain', 'sum__num'); + + // undo - back to drill by state + interceptV1ChartData('drillByUndo'); + interceptFormDataKey(); + cy.get('@drillByModal') + .find('.ant-breadcrumb') + .should('be.visible') + .and('contain', 'gender (boy)') + .and('contain', '/') + .and('contain', 'state (CA)') + .and('contain', 'name') + .contains('state (CA)') + .click(); + cy.wait('@drillByUndo').then(intercepted => { + verifyExpectedFormData(intercepted, { + groupby: ['state'], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: 'boy', + expressionType: 'SIMPLE', + operator: '==', + operatorId: 'EQUALS', + subject: 'gender', + }, + ], + }); + }); + + cy.get('@drillByModal') + .find('[data-test="drill-by-chart"]') + .should('be.visible') + .and('not.contain', 'name') + .and('contain', 'state') + .and('contain', 'sum__num'); + + cy.get('@drillByModal') + .find('.ant-breadcrumb') + .should('be.visible') + .and('contain', 'gender (boy)') + .and('contain', '/') + .and('not.contain', 'state (CA)') + .and('not.contain', 'name') + .and('contain', 'state'); + + cy.get('@drillByModal') + .find('[data-test="drill-by-display-toggle"]') + .contains('Table') + .click(); + + cy.getBySel('drill-by-chart').should('not.exist'); + + cy.get('@drillByModal') + .find('[data-test="drill-by-results-table"]') + .should('be.visible'); + + cy.wait('@formDataKey').then(intercept => { + cy.get('@drillByModal') + .contains('Edit chart') + .should('have.attr', 'href') + .and( + 'contain', + `/explore/?form_data_key=${intercept.response?.body?.key}`, + ); + }); + }); + }); + + describe('Tier 1 charts', () => { + before(() => { + closeModal(); + openTopLevelTab('Tier 1'); + SUPPORTED_TIER1_CHARTS.forEach(waitForChartLoad); + }); + + it('Pivot Table', () => { + openTableContextMenu('boy', "[data-test-viz-type='pivot_table_v2']"); + drillBy('name').then(intercepted => { + verifyExpectedFormData(intercepted, { + groupbyRows: ['state'], + groupbyColumns: ['name'], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: 'boy', + expressionType: 'SIMPLE', + operator: '==', + operatorId: 'EQUALS', + subject: 'gender', + }, + ], + }); + }); + + cy.getBySel('"Drill by: Pivot Table-modal"').as('drillByModal'); + + cy.get('@drillByModal') + .find('.draggable-trigger') + .should('contain', 'Drill by: Pivot Table'); + + cy.get('@drillByModal') + .find('.ant-breadcrumb') + .should('be.visible') + .and('contain', 'gender (boy)') + .and('contain', '/') + .and('contain', 'name'); + + cy.get('@drillByModal') + .find('[data-test="drill-by-chart"]') + .should('be.visible') + .and('contain', 'state') + .and('contain', 'name') + .and('contain', 'sum__num') + .and('not.contain', 'Gender'); + + openTableContextMenu('CA', '[data-test="drill-by-chart"]'); + drillBy('ds').then(intercepted => { + verifyExpectedFormData(intercepted, { + groupbyColumns: ['name'], + groupbyRows: ['ds'], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: 'boy', + expressionType: 'SIMPLE', + operator: '==', + operatorId: 'EQUALS', + subject: 'gender', + }, + { + clause: 'WHERE', + comparator: 'CA', + expressionType: 'SIMPLE', + operator: '==', + operatorId: 'EQUALS', + subject: 'state', + }, + ], + }); + }); + + cy.get('@drillByModal') + .find('[data-test="drill-by-chart"]') + .should('be.visible') + .and('contain', 'name') + .and('contain', 'ds') + .and('contain', 'sum__num') + .and('not.contain', 'state'); + + interceptV1ChartData('drillByUndo'); + + cy.get('@drillByModal') + .find('.ant-breadcrumb') + .should('be.visible') + .and('contain', 'gender (boy)') + .and('contain', '/') + .and('contain', 'name (CA)') + .and('contain', 'ds') + .contains('name (CA)') + .click(); + cy.wait('@drillByUndo').then(intercepted => { + verifyExpectedFormData(intercepted, { + groupbyRows: ['state'], + groupbyColumns: ['name'], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: 'boy', + expressionType: 'SIMPLE', + operator: '==', + operatorId: 'EQUALS', + subject: 'gender', + }, + ], + }); + }); + + cy.get('@drillByModal') + .find('[data-test="drill-by-chart"]') + .should('be.visible') + .and('not.contain', 'ds') + .and('contain', 'state') + .and('contain', 'name') + .and('contain', 'sum__num'); + + cy.get('@drillByModal') + .find('.ant-breadcrumb') + .should('be.visible') + .and('contain', 'gender (boy)') + .and('contain', '/') + .and('not.contain', 'name (CA)') + .and('not.contain', 'ds') + .and('contain', 'name'); + }); + + it('Line chart', () => { + testEchart('echarts_timeseries_line', 'Time-Series Line Chart', [ + [70, 93], + [70, 93], + ]); + }); + + it('Area Chart', () => { + testEchart('echarts_area', 'Time-Series Area Chart', [ + [70, 93], + [70, 93], + ]); + }); + + it('Time-Series Scatter Chart', () => { + testEchart('echarts_timeseries_scatter', 'Time-Series Scatter Chart', [ + [70, 93], + [70, 93], + ]); + }); + + it('Time-Series Bar Chart V2', () => { + testEchart('echarts_timeseries_bar', 'Time-Series Bar Chart V2', [ + [70, 94], + [362, 68], + ]); + }); + + it('Pie Chart', () => { + testEchart('pie', 'Pie Chart', [ + [243, 167], + [534, 248], + ]); + }); + }); + + describe('Tier 2 charts', () => { + before(() => { + closeModal(); + openTopLevelTab('Tier 2'); + SUPPORTED_TIER2_CHARTS.forEach(waitForChartLoad); + }); + + it('Box Plot Chart', () => { + testEchart( + 'box_plot', + 'Box Plot Chart', + [ + [139, 277], + [787, 441], + ], + 'ds', + ); + }); + + it('Time-Series Generic Chart', () => { + testEchart('echarts_timeseries', 'Time-Series Generic Chart', [ + [70, 93], + [70, 93], + ]); + }); + + it('Time-Series Smooth Line Chart', () => { + testEchart('echarts_timeseries_smooth', 'Time-Series Smooth Line Chart', [ + [70, 93], + [70, 93], + ]); + }); + + it('Time-Series Step Line Chart', () => { + testEchart('echarts_timeseries_step', 'Time-Series Step Line Chart', [ + [70, 93], + [70, 93], + ]); + }); + + it('Funnel Chart', () => { + testEchart('funnel', 'Funnel Chart', [ + [154, 80], + [421, 39], + ]); + }); + + it('Gauge Chart', () => { + testEchart('gauge_chart', 'Gauge Chart', [ + [151, 95], + [300, 143], + ]); + }); + + it('Radar Chart', () => { + testEchart('radar', 'Radar Chart', [ + [182, 49], + [423, 91], + ]); + }); + + it('Treemap V2 Chart', () => { + testEchart('treemap_v2', 'Treemap V2 Chart', [ + [145, 84], + [220, 105], + ]); + }); + + it('Mixed Chart', () => { + cy.get('[data-test-viz-type="mixed_timeseries"] canvas').then($canvas => { + // click 'boy' + cy.wrap($canvas) + .scrollIntoView() + .trigger('mouseover', 70, 93) + .rightclick(70, 93); + + drillBy('name').then(intercepted => { + const { queries } = intercepted.request.body; + expect(queries[0].columns).to.eql(['name']); + expect(queries[0].filters).to.eql([ + { col: 'gender', op: '==', val: 'boy' }, + ]); + expect(queries[1].columns).to.eql(['state']); + expect(queries[1].filters).to.eql([]); + }); + + cy.getBySel('"Drill by: Mixed Chart-modal"').as('drillByModal'); + + cy.get('@drillByModal') + .find('.draggable-trigger') + .should('contain', 'Mixed Chart'); + + cy.get('@drillByModal') + .find('.ant-breadcrumb') + .should('be.visible') + .and('contain', 'gender (boy)') + .and('contain', '/') + .and('contain', 'name'); + + cy.get('@drillByModal') + .find('[data-test="drill-by-chart"]') + .should('be.visible'); + + // further drill + cy.get(`[data-test="drill-by-chart"] canvas`).then($canvas => { + // click second query + cy.wrap($canvas) + .scrollIntoView() + .trigger('mouseover', 246, 114) + .rightclick(246, 114); + + drillBy('ds').then(intercepted => { + const { queries } = intercepted.request.body; + expect(queries[0].columns).to.eql(['name']); + expect(queries[0].filters).to.eql([ + { col: 'gender', op: '==', val: 'boy' }, + ]); + expect(queries[1].columns).to.eql(['ds']); + expect(queries[1].filters).to.eql([ + { col: 'state', op: '==', val: 'other' }, + ]); + }); + + cy.get('@drillByModal') + .find('[data-test="drill-by-chart"]') + .should('be.visible'); + + // undo - back to drill by state + interceptV1ChartData('drillByUndo'); + cy.get('@drillByModal') + .find('.ant-breadcrumb') + .should('be.visible') + .and('contain', 'gender (boy)') + .and('contain', '/') + .and('contain', 'name (other)') + .and('contain', 'ds') + .contains('name (other)') + .click(); + + cy.wait('@drillByUndo').then(intercepted => { + const { queries } = intercepted.request.body; + expect(queries[0].columns).to.eql(['name']); + expect(queries[0].filters).to.eql([ + { col: 'gender', op: '==', val: 'boy' }, + ]); + expect(queries[1].columns).to.eql(['state']); + expect(queries[1].filters).to.eql([]); + }); + + cy.get('@drillByModal') + .find('.ant-breadcrumb') + .should('be.visible') + .and('contain', 'gender (boy)') + .and('contain', '/') + .and('not.contain', 'name (other)') + .and('not.contain', 'ds') + .and('contain', 'name'); + + cy.get('@drillByModal') + .find('[data-test="drill-by-chart"]') + .should('be.visible'); + }); + }); + }); + }); +}); diff --git a/superset-frontend/cypress-base/cypress/e2e/dashboard/drilltodetail.test.ts b/superset-frontend/cypress-base/cypress/e2e/dashboard/drilltodetail.test.ts index 2ab4966d5..ff1872333 100644 --- a/superset-frontend/cypress-base/cypress/e2e/dashboard/drilltodetail.test.ts +++ b/superset-frontend/cypress-base/cypress/e2e/dashboard/drilltodetail.test.ts @@ -18,7 +18,11 @@ */ import { waitForChartLoad } from 'cypress/utils'; import { SUPPORTED_CHARTS_DASHBOARD } from 'cypress/utils/urls'; -import { SUPPORTED_TIER1_CHARTS, SUPPORTED_TIER2_CHARTS } from './utils'; +import { + openTopLevelTab, + SUPPORTED_TIER1_CHARTS, + SUPPORTED_TIER2_CHARTS, +} from './utils'; function interceptSamples() { cy.intercept(`/datasource/samples*`).as('samples'); @@ -77,10 +81,6 @@ function closeModal() { }); } -function setTopLevelTab(tabName: string) { - cy.get("div#TABS-TOP div[role='tab']").contains(tabName).click(); -} - function testTimeChart(vizType: string) { interceptSamples(); @@ -139,7 +139,7 @@ describe('Drill to detail modal', () => { describe('Tier 1 charts', () => { before(() => { cy.visit(SUPPORTED_CHARTS_DASHBOARD); - setTopLevelTab('Tier 1'); + openTopLevelTab('Tier 1'); SUPPORTED_TIER1_CHARTS.forEach(waitForChartLoad); }); @@ -438,7 +438,7 @@ describe('Drill to detail modal', () => { describe('Tier 2 charts', () => { before(() => { cy.visit(SUPPORTED_CHARTS_DASHBOARD); - setTopLevelTab('Tier 2'); + openTopLevelTab('Tier 2'); SUPPORTED_TIER2_CHARTS.forEach(waitForChartLoad); }); diff --git a/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts b/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts index 211ae88ff..159e9368e 100644 --- a/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts +++ b/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts @@ -37,10 +37,24 @@ export const SUPPORTED_TIER1_CHARTS = [ { name: 'Big Number', viz: 'big_number_total' }, { name: 'Big Number with Trendline', viz: 'big_number' }, { name: 'Pie Chart', viz: 'pie' }, + { name: 'Table', viz: 'table' }, + { name: 'Pivot Table', viz: 'pivot_table_v2' }, + { name: 'Time-Series Line Chart', viz: 'echarts_timeseries_line' }, + { name: 'Time-Series Area Chart', viz: 'echarts_area' }, + { name: 'Time-Series Scatter Chart', viz: 'echarts_timeseries_scatter' }, + { name: 'Time-Series Bar Chart V2', viz: 'echarts_timeseries_bar' }, ] as ChartSpec[]; export const SUPPORTED_TIER2_CHARTS = [ { name: 'Box Plot Chart', viz: 'box_plot' }, + { name: 'Time-Series Generic Chart', viz: 'echarts_timeseries' }, + { name: 'Time-Series Smooth Line Chart', viz: 'echarts_timeseries_smooth' }, + { name: 'Time-Series Step Line Chart', viz: 'echarts_timeseries_step' }, + { name: 'Funnel Chart', viz: 'funnel' }, + { name: 'Gauge Chart', viz: 'gauge_chart' }, + { name: 'Radar Chart', viz: 'radar' }, + { name: 'Treemap V2 Chart', viz: 'treemap_v2' }, + { name: 'Mixed Chart', viz: 'mixed_timeseries' }, ] as ChartSpec[]; export const testItems = { @@ -515,3 +529,7 @@ export function openTab(tabComponentIndex: number, tabIndex: number) { .eq(tabIndex) .click(); } + +export const openTopLevelTab = (tabName: string) => { + cy.get("div#TABS-TOP div[role='tab']").contains(tabName).click(); +}; diff --git a/superset-frontend/cypress-base/cypress/e2e/explore/utils.ts b/superset-frontend/cypress-base/cypress/e2e/explore/utils.ts index 0a1dc50fa..95af89db5 100644 --- a/superset-frontend/cypress-base/cypress/e2e/explore/utils.ts +++ b/superset-frontend/cypress-base/cypress/e2e/explore/utils.ts @@ -35,13 +35,17 @@ export function interceptUpdate() { cy.intercept('PUT', `/api/v1/chart/*`).as('update'); } -export function interceptPost() { - cy.intercept('POST', `/api/v1/chart/`).as('post'); +export const interceptV1ChartData = (alias = 'v1Data') => { + cy.intercept('/api/v1/chart/data*').as(alias); +}; + +export function interceptExploreJson(alias = 'getJson') { + cy.intercept('POST', `/superset/explore_json/**`).as(alias); } -export function interceptExploreJson() { - cy.intercept('POST', `/superset/explore_json/**`).as('getJson'); -} +export const interceptFormDataKey = () => { + cy.intercept('POST', '/api/v1/explore/form_data').as('formDataKey'); +}; export function interceptExploreGet() { cy.intercept({ diff --git a/superset-frontend/src/components/Chart/DrillBy/DrillByChart.tsx b/superset-frontend/src/components/Chart/DrillBy/DrillByChart.tsx index 91faa05c9..f58a646db 100644 --- a/superset-frontend/src/components/Chart/DrillBy/DrillByChart.tsx +++ b/superset-frontend/src/components/Chart/DrillBy/DrillByChart.tsx @@ -54,6 +54,7 @@ export default function DrillByChart({ height: 100%; min-height: 0; `} + data-test="drill-by-chart" > { box-shadow: none; } `} + data-test="drill-by-display-toggle" > { diff --git a/superset-frontend/src/components/Chart/DrillBy/useResultsTableView.tsx b/superset-frontend/src/components/Chart/DrillBy/useResultsTableView.tsx index 2778fab72..b424b95ea 100644 --- a/superset-frontend/src/components/Chart/DrillBy/useResultsTableView.tsx +++ b/superset-frontend/src/components/Chart/DrillBy/useResultsTableView.tsx @@ -40,7 +40,7 @@ export const useResultsTableView = ( } if (chartDataResult.length === 1) { return ( - + + {chartDataResult.map((res, index) => ( diff --git a/superset/examples/supported_charts_dashboard.py b/superset/examples/supported_charts_dashboard.py index 54aa650d5..e6d7557de 100644 --- a/superset/examples/supported_charts_dashboard.py +++ b/superset/examples/supported_charts_dashboard.py @@ -335,7 +335,7 @@ def create_slices(tbl: SqlaTable) -> List[Slice]: viz_type="mixed_timeseries", metrics=["sum__num"], groupby=["gender"], - metrics_b=["count"], + metrics_b=["sum__num"], groupby_b=["state"], ), ), diff --git a/tests/integration_tests/superset_test_config.py b/tests/integration_tests/superset_test_config.py index 19c2cc000..c3f9b350f 100644 --- a/tests/integration_tests/superset_test_config.py +++ b/tests/integration_tests/superset_test_config.py @@ -61,7 +61,7 @@ PRESTO_POLL_INTERVAL = 0.1 HIVE_POLL_INTERVAL = 0.1 SQL_MAX_ROW = 10000 -SQLLAB_CTAS_NO_LIMIT = True # SQL_MAX_ROW will not take affect for the CTA queries +SQLLAB_CTAS_NO_LIMIT = True # SQL_MAX_ROW will not take effect for the CTA queries FEATURE_FLAGS = { **FEATURE_FLAGS, "foo": "bar", @@ -71,6 +71,7 @@ FEATURE_FLAGS = { "ALERT_REPORTS": True, "DASHBOARD_NATIVE_FILTERS": True, "DRILL_TO_DETAIL": True, + "DRILL_BY": True, "HORIZONTAL_FILTER_BAR": True, }