From f017f98b88349a1d333509a4ab60eec33f1065db Mon Sep 17 00:00:00 2001 From: Geido <60598000+geido@users.noreply.github.com> Date: Mon, 29 Aug 2022 11:25:27 +0300 Subject: [PATCH] chore: E2E tests for the Drill to detail modal (#21187) * Add example ECharts Dashboard * [WIP] E2E test * Add echarts interactions * Lint * DRY --- .../integration/dashboard/dashboard.helper.ts | 13 +- .../dashboard/drilltodetail.test.ts | 271 ++++++++++++++++++ .../BigNumberWithTrendline/transformProps.ts | 1 + .../DrillDetailPane/TableControls.tsx | 3 +- .../components/RowCountLabel/index.tsx | 12 +- superset/cli/examples.py | 3 + superset/examples/data_loading.py | 1 + superset/examples/echarts_dashboard.py | 250 ++++++++++++++++ .../integration_tests/superset_test_config.py | 1 + 9 files changed, 548 insertions(+), 7 deletions(-) create mode 100644 superset-frontend/cypress-base/cypress/integration/dashboard/drilltodetail.test.ts create mode 100644 superset/examples/echarts_dashboard.py diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts index 498853164e5a8..486833c72be65 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts @@ -23,6 +23,7 @@ export const WORLD_HEALTH_DASHBOARD = '/superset/dashboard/world_health/'; export const USA_BIRTH_NAMES_DASHBOARD = '/superset/dashboard/births/'; export const testDashboard = '/superset/dashboard/538/'; export const TABBED_DASHBOARD = '/superset/dashboard/tabbed_dash/'; +export const ECHARTS_DASHBOARD = '/superset/dashboard/echarts_dash/'; export const testItems = { dashboard: 'Cypress test Dashboard', @@ -73,6 +74,14 @@ export const WORLD_HEALTH_CHARTS = [ { name: 'Box plot', viz: 'box_plot' }, ] as const; +export const ECHARTS_CHARTS = [ + { name: 'Number of Girls', viz: 'big_number_total' }, + { name: 'Participants', viz: 'big_number' }, + { name: 'Box plot', viz: 'box_plot' }, + { name: 'Genders', viz: 'pie' }, + { name: 'Energy Force Layout', viz: 'graph_chart' }, +] as const; + /** Used to specify charts expected by the test suite */ export interface ChartSpec { name: string; @@ -81,7 +90,7 @@ export interface ChartSpec { export function getChartGridComponent({ name, viz }: ChartSpec) { return cy - .get(`[data-test="chart-grid-component"][data-test-chart-name="${name}"]`) + .get(`[data-test-chart-name="${name}"]`) .should('have.attr', 'data-test-viz-type', viz); } @@ -92,7 +101,7 @@ export function waitForChartLoad(chart: ChartSpec) { return ( cy // this id only becomes visible when the chart is loaded - .get(`[data-test="chart-grid-component"] #chart-id-${chartId}`, { + .get(`#chart-id-${chartId}`, { timeout: 30000, }) .should('be.visible') diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/drilltodetail.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/drilltodetail.test.ts new file mode 100644 index 0000000000000..b3dc40bc3500f --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/drilltodetail.test.ts @@ -0,0 +1,271 @@ +/** + * 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 { + waitForChartLoad, + ECHARTS_CHARTS, + ECHARTS_DASHBOARD, +} from './dashboard.helper'; + +function interceptSamples() { + cy.intercept(`/datasource/samples*`).as('samples'); +} + +function openModalFromMenu(chartType: string) { + interceptSamples(); + + cy.get( + `[data-test-viz-type='${chartType}'] [aria-label='More Options']`, + ).click(); + cy.get('.ant-dropdown') + .not('.ant-dropdown-hidden') + .find("[role='menu'] [role='menuitem']") + .eq(5) + .should('contain', 'Drill to detail') + .click(); + cy.wait('@samples'); +} + +function openModalFromChartContext(targetMenuItem: string) { + interceptSamples(); + + cy.get('.ant-dropdown') + .not('.ant-dropdown-hidden') + .find("[role='menu'] [role='menuitem']") + .should('contain', targetMenuItem) + .click(); + cy.wait('@samples'); +} + +describe('Drill to detail modal', () => { + beforeEach(() => { + cy.login(); + cy.visit(ECHARTS_DASHBOARD); + ECHARTS_CHARTS.forEach(waitForChartLoad); + }); + + it('opens the modal from the context menu', () => { + openModalFromMenu('big_number_total'); + + cy.get("[role='dialog'] .draggable-trigger").should( + 'contain', + 'Drill to detail: Number of Girls', + ); + }); + + it('refreshes the data', () => { + openModalFromMenu('big_number_total'); + // move to the last page + cy.get(".pagination-container [role='navigation'] [role='button']") + .eq(7) + .click(); + cy.wait('@samples'); + // reload + cy.get("[aria-label='reload']").click(); + cy.wait('@samples'); + // make sure it started back from first page + cy.get(".pagination-container [role='navigation'] li.active").should( + 'contain', + '1', + ); + }); + + it('paginates', () => { + openModalFromMenu('big_number_total'); + // checking the data + cy.get("[data-test='row-count-label']").should('contain', '36.4k rows'); + cy.get("[role='rowgroup'] [role='row']") + .should('have.length', 50) + .then($rows => { + expect($rows).to.contain('Amy'); + }); + // checking the paginated data + cy.get(".pagination-container [role='navigation'] [role='button']") + .should('have.length', 9) + .then($pages => { + expect($pages).to.contain('1'); + expect($pages).to.contain('729'); + }); + cy.get(".pagination-container [role='navigation'] [role='button']") + .eq(7) + .click(); + cy.wait('@samples'); + cy.get("[role='rowgroup'] [role='row']") + .should('have.length', 46) + .then($rows => { + expect($rows).to.contain('Victoria'); + }); + }); + + it('clears filters', () => { + interceptSamples(); + + // opens the modal by clicking on the box on the chart + cy.get("[data-test-viz-type='box_plot'] canvas").then($canvas => { + const canvasWidth = $canvas.width() || 0; + const canvasHeight = $canvas.height() || 0; + const canvasCenterX = canvasWidth / 6; + const canvasCenterY = canvasHeight / 6; + + cy.wrap($canvas) + .scrollIntoView() + .rightclick(canvasCenterX, canvasCenterY, { force: true }); + + openModalFromChartContext('Drill to detail by East Asia & Pacific'); + + // checking the filter + cy.get("[data-test='filter-val']").should( + 'contain', + 'East Asia & Pacific', + ); + cy.get("[data-test='row-count-label']").should('contain', '1.98k rows'); + cy.get(".pagination-container [role='navigation'] [role='button']") + .should('have.length', 9) + .then($pages => { + expect($pages).to.contain('1'); + expect($pages).to.contain('40'); + }); + + // close the filter and test that data was reloaded + cy.get("[data-test='filter-col']").find("[aria-label='close']").click(); + cy.wait('@samples'); + cy.get("[data-test='row-count-label']").should('contain', '11.8k rows'); + cy.get(".pagination-container [role='navigation'] li.active").should( + 'contain', + '1', + ); + cy.get(".pagination-container [role='navigation'] [role='button']") + .should('have.length', 9) + .then($pages => { + expect($pages).to.contain('1'); + expect($pages).to.contain('236'); + }); + }); + }); + + describe('Time-series Bar Chart V2', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + cy.get("[data-test-viz-type='echarts_timeseries_bar'] canvas").then( + $canvas => { + cy.wrap($canvas) + .scrollIntoView() + .rightclick(70, 100, { force: true }); + cy.get('.ant-dropdown') + .not('.ant-dropdown-hidden') + .find("[role='menu'] [role='menuitem']") + .should('have.length', 3) + .then($menuitems => { + expect($menuitems).to.contain('Drill to detail by 1965'); + expect($menuitems).to.contain('Drill to detail by boy'); + expect($menuitems).to.contain('Drill to detail by all'); + }) + .eq(2) + .click(); + cy.wait('@samples'); + + cy.get("[data-test='filter-val']").then($filters => { + expect($filters).to.contain('1965'); + expect($filters).to.contain('boy'); + }); + }, + ); + }); + }); + + describe('Box plot', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + // opens the modal by clicking on the box on the chart + cy.get("[data-test-viz-type='box_plot'] canvas").then($canvas => { + const canvasWidth = $canvas.width() || 0; + const canvasHeight = $canvas.height() || 0; + const canvasCenterX = canvasWidth / 6; + const canvasCenterY = canvasHeight / 6; + + cy.wrap($canvas) + .scrollIntoView() + .rightclick(canvasCenterX, canvasCenterY, { force: true }); + + openModalFromChartContext('Drill to detail by East Asia & Pacific'); + + // checking the filter + cy.get("[data-test='filter-val']").should( + 'contain', + 'East Asia & Pacific', + ); + }); + }); + }); + + describe('Pie', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + // opens the modal by clicking on the slice of the Pie chart + cy.get("[data-test-viz-type='pie'] canvas").then($canvas => { + const canvasWidth = $canvas.width() || 0; + const canvasHeight = $canvas.height() || 0; + const canvasCenterX = canvasWidth / 2; + const canvasCenterY = canvasHeight / 2; + + cy.wrap($canvas) + .scrollIntoView() + .rightclick(canvasCenterX, canvasCenterY, { force: true }); + + openModalFromChartContext('Drill to detail by boy'); + + // checking the filtered and paginated data + cy.get("[data-test='filter-val']").should('contain', 'boy'); + }); + }); + }); + + describe('Big number total', () => { + it('opens the modal with no filters', () => { + interceptSamples(); + + // opens the modal by clicking on the number on the chart + cy.get( + "[data-test-viz-type='big_number_total'] .header-line", + ).rightclick(); + + openModalFromChartContext('Drill to detail'); + + cy.get("[data-test='filter-val']").should('not.exist'); + }); + }); + + describe('Big number with trendline', () => { + it('opens the modal with the correct data', () => { + interceptSamples(); + + // opens the modal by clicking on the number + cy.get("[data-test-viz-type='big_number'] .header-line").rightclick(); + + openModalFromChartContext('Drill to detail'); + + cy.get("[data-test='filter-val']").should('not.exist'); + + // TODO: test clicking on a trendline + // Cypress is refusing to rightclick on the dot + }); + }); +}); diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts index 003e4e70eb27c..98fe277486460 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts @@ -195,6 +195,7 @@ export default function transformProps( type: 'line', smooth: true, symbol: 'circle', + symbolSize: 10, showSymbol: false, color: mainColor, areaStyle: { diff --git a/superset-frontend/src/dashboard/components/DrillDetailPane/TableControls.tsx b/superset-frontend/src/dashboard/components/DrillDetailPane/TableControls.tsx index 9b0e072379085..26965a2f18dd1 100644 --- a/superset-frontend/src/dashboard/components/DrillDetailPane/TableControls.tsx +++ b/superset-frontend/src/dashboard/components/DrillDetailPane/TableControls.tsx @@ -105,6 +105,7 @@ export default function TableControls({ margin-bottom: ${theme.gridUnit * 4}px; line-height: 1.2; `} + data-test="filter-col" > {colName} - {val} + {val} ))} diff --git a/superset-frontend/src/explore/components/RowCountLabel/index.tsx b/superset-frontend/src/explore/components/RowCountLabel/index.tsx index 3597e49724752..be41be0ba67de 100644 --- a/superset-frontend/src/explore/components/RowCountLabel/index.tsx +++ b/superset-frontend/src/explore/components/RowCountLabel/index.tsx @@ -35,10 +35,14 @@ export default function RowCountLabel(props: RowCountLabelProps) { limitReached || (rowcount === 0 && !loading) ? 'danger' : 'default'; const formattedRowCount = getNumberFormatter()(rowcount); const label = ( -