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 = (
-