From a0fd80194ad80e04374764f9411d24bca53c7956 Mon Sep 17 00:00:00 2001 From: Rafael Wendel Date: Mon, 19 Oct 2020 18:18:56 -0300 Subject: [PATCH 01/10] created bar-chart e2e test boilerplate --- .../integration/visualizations/chart_spec.js | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 client/cypress/integration/visualizations/chart_spec.js diff --git a/client/cypress/integration/visualizations/chart_spec.js b/client/cypress/integration/visualizations/chart_spec.js new file mode 100644 index 0000000000..783459b5ea --- /dev/null +++ b/client/cypress/integration/visualizations/chart_spec.js @@ -0,0 +1,112 @@ +/* global cy */ + +import { getWidgetTestId } from "../../support/dashboard"; + +const SQL = ` + SELECT 'a' AS stage1, 'a1' AS stage2, 11 AS value UNION ALL + SELECT 'a' AS stage1, 'a2' AS stage2, 12 AS value UNION ALL + SELECT 'a' AS stage1, 'a3' AS stage2, 45 AS value UNION ALL + SELECT 'a' AS stage1, 'a4' AS stage2, 54 AS value UNION ALL + SELECT 'b' AS stage1, 'b1' AS stage2, 33 AS value UNION ALL + SELECT 'b' AS stage1, 'b2' AS stage2, 73 AS value UNION ALL + SELECT 'b' AS stage1, 'b3' AS stage2, 90 AS value UNION ALL + SELECT 'c' AS stage1, 'c1' AS stage2, 19 AS value UNION ALL + SELECT 'c' AS stage1, 'c2' AS stage2, 92 AS value UNION ALL + SELECT 'c' AS stage1, 'c3' AS stage2, 63 AS value UNION ALL + SELECT 'c' AS stage1, 'c4' AS stage2, 44 AS value\ +`; + +function createChartThroughUI(visualizationName) { + cy.getByTestId("NewVisualization").click(); + cy.getByTestId("VisualizationType").selectAntdOption("VisualizationType.CHART"); + cy.getByTestId("VisualizationName") + .clear() + .type(visualizationName); + + // Checks for TabbedEditor standard tabs + cy.getByTestId("Chart.GlobalSeriesType").should("exist"); + + cy.getByTestId("VisualizationEditor.Tabs.Series").click(); + cy.getByTestId("VisualizationEditor") + .find("table") + .should("exist"); + + cy.getByTestId("VisualizationEditor.Tabs.Colors").click(); + cy.getByTestId("VisualizationEditor") + .find("table") + .should("exist"); + + cy.getByTestId("VisualizationEditor.Tabs.DataLabels").click(); + cy.getByTestId("VisualizationEditor") + .getByTestId("Chart.DataLabels.ShowDataLabels") + .should("exist"); + + cy.getByTestId("VisualizationEditor.Tabs.General").click(); +} + +function assertAxesAndAddLabels() { + cy.getByTestId("VisualizationEditor.Tabs.XAxis").click(); + cy.getByTestId("Chart.XAxis.Type") + .contains(".ant-select-selection-item", "Auto Detect") + .should("exist"); + + cy.getByTestId("Chart.XAxis.Name") + .clear() + .type("Stage 1"); + + cy.getByTestId("VisualizationEditor.Tabs.YAxis").click(); + cy.getByTestId("Chart.LeftYAxis.Type") + .contains(".ant-select-selection-item", "Linear") + .should("exist"); + + cy.getByTestId("Chart.LeftYAxis.Name") + .clear() + .type("Value"); +} + +describe("Chart", () => { + beforeEach(() => { + cy.login(); + cy.createQuery({ name: "Chart Visualization", query: SQL }) + .its("id") + .as("queryId"); + }); + + it("creates Bar Chart", function() { + cy.visit(`queries/${this.queryId}/source`); + cy.getByTestId("ExecuteButton").click(); + + const visualizationName = "Bar Chart"; + + createChartThroughUI(visualizationName); + + // standard chart should be bar + cy.getByTestId("Chart.GlobalSeriesType").contains(".ant-select-selection-item", "Bar"); + + cy.getByTestId("VisualizationPreview") + .find("g.plot") + .should("exist") + .find("g.points") + .should("not.exist"); + + cy.getByTestId("Chart.ColumnMapping.y").selectAntdOption("Chart.ColumnMapping.y.value"); + cy.getByTestId("Chart.ColumnMapping.x").selectAntdOption("Chart.ColumnMapping.x.stage1"); + + cy.getByTestId("VisualizationPreview") + .find("g.plot") + .should("exist") + .find("g.points") + .should("exist"); + + // checks for axes default scales and set custom labels + assertAxesAndAddLabels(); + + cy.getByTestId("EditVisualizationDialog") + .contains("button", "Save") + .click(); + + cy.getByTestId("QueryPageVisualizationTabs") + .contains("span", visualizationName) + .should("exist"); + }); +}); From 5d22dfba74c9c5b08ad04dd7935db1424ef2b0aa Mon Sep 17 00:00:00 2001 From: Rafael Wendel Date: Mon, 2 Nov 2020 16:43:54 -0300 Subject: [PATCH 02/10] refactored assertions --- .../integration/visualizations/chart_spec.js | 68 +++++++++++-------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/client/cypress/integration/visualizations/chart_spec.js b/client/cypress/integration/visualizations/chart_spec.js index 783459b5ea..ba25aff7ac 100644 --- a/client/cypress/integration/visualizations/chart_spec.js +++ b/client/cypress/integration/visualizations/chart_spec.js @@ -16,14 +16,33 @@ const SQL = ` SELECT 'c' AS stage1, 'c4' AS stage2, 44 AS value\ `; -function createChartThroughUI(visualizationName) { +/** + * Asserts the canvas exists, then captures the g.points element, which should be generated by plotly and asserts whether it exists + * @param should Passed to should expression after plot points are captured + */ +function assertPlot(should = "exist") { + cy.getByTestId("VisualizationPreview") + .find("g.plot") + .should("exist") + .find("g.points") + .should(should); +} + +function createChartThroughUI(visualizationName, chartSpecificAssertionFn = () => {}) { cy.getByTestId("NewVisualization").click(); cy.getByTestId("VisualizationType").selectAntdOption("VisualizationType.CHART"); cy.getByTestId("VisualizationName") .clear() .type(visualizationName); - // Checks for TabbedEditor standard tabs + chartSpecificAssertionFn(); + + cy.getByTestId("EditVisualizationDialog") + .contains("button", "Save") + .click(); +} + +function assertTabbedEditor(chartSpecificTabbedEditorAssertionFn = () => {}) { cy.getByTestId("Chart.GlobalSeriesType").should("exist"); cy.getByTestId("VisualizationEditor.Tabs.Series").click(); @@ -41,6 +60,8 @@ function createChartThroughUI(visualizationName) { .getByTestId("Chart.DataLabels.ShowDataLabels") .should("exist"); + chartSpecificTabbedEditorAssertionFn(); + cy.getByTestId("VisualizationEditor.Tabs.General").click(); } @@ -72,41 +93,34 @@ describe("Chart", () => { .as("queryId"); }); - it("creates Bar Chart", function() { + it("creates Bar charts", function() { cy.visit(`queries/${this.queryId}/source`); cy.getByTestId("ExecuteButton").click(); - const visualizationName = "Bar Chart"; - - createChartThroughUI(visualizationName); + const barChartAssertionFunction = () => { + // checks for TabbedEditor standard tabs + assertTabbedEditor(); - // standard chart should be bar - cy.getByTestId("Chart.GlobalSeriesType").contains(".ant-select-selection-item", "Bar"); + // standard chart should be bar + cy.getByTestId("Chart.GlobalSeriesType").contains(".ant-select-selection-item", "Bar"); - cy.getByTestId("VisualizationPreview") - .find("g.plot") - .should("exist") - .find("g.points") - .should("not.exist"); + // checks the plot canvas exists and is empty + assertPlot("not.exist"); - cy.getByTestId("Chart.ColumnMapping.y").selectAntdOption("Chart.ColumnMapping.y.value"); - cy.getByTestId("Chart.ColumnMapping.x").selectAntdOption("Chart.ColumnMapping.x.stage1"); - - cy.getByTestId("VisualizationPreview") - .find("g.plot") - .should("exist") - .find("g.points") - .should("exist"); + // creates a chart and checks it is plotted + cy.getByTestId("Chart.ColumnMapping.y").selectAntdOption("Chart.ColumnMapping.y.value"); + cy.getByTestId("Chart.ColumnMapping.x").selectAntdOption("Chart.ColumnMapping.x.stage1"); + assertPlot("exist"); - // checks for axes default scales and set custom labels - assertAxesAndAddLabels(); + // checks for axes default scales and set custom labels + assertAxesAndAddLabels(); + }; - cy.getByTestId("EditVisualizationDialog") - .contains("button", "Save") - .click(); + const basicChartName = "Basic Bar Chart" + const basicBarChart = createChartThroughUI(basicChartName, barChartAssertionFunction); cy.getByTestId("QueryPageVisualizationTabs") - .contains("span", visualizationName) + .contains("span", basicChartName) .should("exist"); }); }); From a546b23808f3847376ac2b1ab468d0076d612010 Mon Sep 17 00:00:00 2001 From: Rafael Wendel Date: Mon, 2 Nov 2020 20:14:28 -0300 Subject: [PATCH 03/10] added snapshots and dashboard --- .../integration/visualizations/chart_spec.js | 78 ++++++++++++++----- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/client/cypress/integration/visualizations/chart_spec.js b/client/cypress/integration/visualizations/chart_spec.js index ba25aff7ac..35b5b1aa30 100644 --- a/client/cypress/integration/visualizations/chart_spec.js +++ b/client/cypress/integration/visualizations/chart_spec.js @@ -1,6 +1,7 @@ /* global cy */ import { getWidgetTestId } from "../../support/dashboard"; +import { get } from "lodash"; const SQL = ` SELECT 'a' AS stage1, 'a1' AS stage2, 11 AS value UNION ALL @@ -17,29 +18,44 @@ const SQL = ` `; /** - * Asserts the canvas exists, then captures the g.points element, which should be generated by plotly and asserts whether it exists + * Asserts the preview canvas exists, then captures the g.points element, which should be generated by plotly and asserts whether it exists * @param should Passed to should expression after plot points are captured */ -function assertPlot(should = "exist") { +function assertPlotPreview(should = "exist") { cy.getByTestId("VisualizationPreview") - .find("g.plot") - .should("exist") - .find("g.points") - .should(should); + .find("g.plot") + .should("exist") + .find("g.points") + .should(should); } -function createChartThroughUI(visualizationName, chartSpecificAssertionFn = () => {}) { +function createChartThroughUI(chartName, chartSpecificAssertionFn = () => {}) { cy.getByTestId("NewVisualization").click(); cy.getByTestId("VisualizationType").selectAntdOption("VisualizationType.CHART"); cy.getByTestId("VisualizationName") .clear() - .type(visualizationName); + .type(chartName); chartSpecificAssertionFn(); + cy.server(); + cy.route("POST", "**/api/visualizations").as("SaveVisualization"); + cy.getByTestId("EditVisualizationDialog") .contains("button", "Save") .click(); + + cy.wait("@SaveVisualization").should("have.property", "status", 200); + + return cy.get("@SaveVisualization").then(xhr => { + const { id, name, options } = xhr.response.body; + + cy.getByTestId("QueryPageVisualizationTabs") + .contains("span", chartName) + .should("exist"); + + return cy.wrap({ id, name, options }); + }); } function assertTabbedEditor(chartSpecificTabbedEditorAssertionFn = () => {}) { @@ -65,7 +81,7 @@ function assertTabbedEditor(chartSpecificTabbedEditorAssertionFn = () => {}) { cy.getByTestId("VisualizationEditor.Tabs.General").click(); } -function assertAxesAndAddLabels() { +function assertAxesAndAddLabels(xaxisLabel, yaxisLabel) { cy.getByTestId("VisualizationEditor.Tabs.XAxis").click(); cy.getByTestId("Chart.XAxis.Type") .contains(".ant-select-selection-item", "Auto Detect") @@ -73,7 +89,7 @@ function assertAxesAndAddLabels() { cy.getByTestId("Chart.XAxis.Name") .clear() - .type("Stage 1"); + .type(xaxisLabel); cy.getByTestId("VisualizationEditor.Tabs.YAxis").click(); cy.getByTestId("Chart.LeftYAxis.Type") @@ -82,7 +98,21 @@ function assertAxesAndAddLabels() { cy.getByTestId("Chart.LeftYAxis.Name") .clear() - .type("Value"); + .type(yaxisLabel); +} + +function createDashboardWithCharts(title, charts, widgetsAssertionFn = () => {}) { + return cy.createDashboard(title).then(dashboard => { + const dashboardUrl = `/dashboards/${dashboard.id}`; + return cy + .all( + charts.map((chart, i) => { + const position = { autoHeight: false, sizeY: 8, sizeX: 3, col: (i % 2) * 3 }; + return () => cy.addWidget(dashboard.id, chart.id, { position }); + }) + ) + .then(widgets => widgetsAssertionFn(widgets, dashboardUrl)); + }); } describe("Chart", () => { @@ -93,6 +123,8 @@ describe("Chart", () => { .as("queryId"); }); + const charts = []; + it("creates Bar charts", function() { cy.visit(`queries/${this.queryId}/source`); cy.getByTestId("ExecuteButton").click(); @@ -105,22 +137,30 @@ describe("Chart", () => { cy.getByTestId("Chart.GlobalSeriesType").contains(".ant-select-selection-item", "Bar"); // checks the plot canvas exists and is empty - assertPlot("not.exist"); + assertPlotPreview("not.exist"); // creates a chart and checks it is plotted cy.getByTestId("Chart.ColumnMapping.y").selectAntdOption("Chart.ColumnMapping.y.value"); cy.getByTestId("Chart.ColumnMapping.x").selectAntdOption("Chart.ColumnMapping.x.stage1"); - assertPlot("exist"); + assertPlotPreview("exist"); // checks for axes default scales and set custom labels - assertAxesAndAddLabels(); + assertAxesAndAddLabels("Stage 1", "Value"); }; - const basicChartName = "Basic Bar Chart" - const basicBarChart = createChartThroughUI(basicChartName, barChartAssertionFunction); + createChartThroughUI("Basic Bar Chart", barChartAssertionFunction).then(basicBarChart => { + charts.push(...Array(8).fill(Cypress.dom.unwrap(basicBarChart))); // temporary, testing behavior for multiple charts + }); + }); - cy.getByTestId("QueryPageVisualizationTabs") - .contains("span", basicChartName) - .should("exist"); + it("takes a snapshot with different configured Charts", function() { + const withDashboardWidgetsAssertionFn = (widgets, dashboardUrl) => { + cy.visit(dashboardUrl); + widgets.forEach(widget => { + cy.getByTestId(getWidgetTestId(widget)).within(() => cy.get("g.points").should("exist")); + }); + cy.percySnapshot("Visualizations - Charts - Bar"); + }; + createDashboardWithCharts("Bar chart visualizations", [...charts], withDashboardWidgetsAssertionFn); }); }); From 0680621e9e96577265636bfdc171cbb4faadf4ee Mon Sep 17 00:00:00 2001 From: Rafael Wendel Date: Fri, 6 Nov 2020 20:31:12 -0300 Subject: [PATCH 04/10] refactored assertions to properly deal with async --- .../integration/visualizations/chart_spec.js | 75 ++++++++++++------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/client/cypress/integration/visualizations/chart_spec.js b/client/cypress/integration/visualizations/chart_spec.js index 35b5b1aa30..7ff4b0ac20 100644 --- a/client/cypress/integration/visualizations/chart_spec.js +++ b/client/cypress/integration/visualizations/chart_spec.js @@ -45,15 +45,14 @@ function createChartThroughUI(chartName, chartSpecificAssertionFn = () => {}) { .contains("button", "Save") .click(); + cy.getByTestId("QueryPageVisualizationTabs") + .contains("span", chartName) + .should("exist"); + cy.wait("@SaveVisualization").should("have.property", "status", 200); return cy.get("@SaveVisualization").then(xhr => { const { id, name, options } = xhr.response.body; - - cy.getByTestId("QueryPageVisualizationTabs") - .contains("span", chartName) - .should("exist"); - return cy.wrap({ id, name, options }); }); } @@ -99,19 +98,23 @@ function assertAxesAndAddLabels(xaxisLabel, yaxisLabel) { cy.getByTestId("Chart.LeftYAxis.Name") .clear() .type(yaxisLabel); + + cy.getByTestId("VisualizationEditor.Tabs.General").click(); } -function createDashboardWithCharts(title, charts, widgetsAssertionFn = () => {}) { - return cy.createDashboard(title).then(dashboard => { +function createDashboardWithCharts(title, chartGetters, widgetsAssertionFn = () => {}) { + cy.createDashboard(title).then(dashboard => { const dashboardUrl = `/dashboards/${dashboard.id}`; - return cy - .all( - charts.map((chart, i) => { - const position = { autoHeight: false, sizeY: 8, sizeX: 3, col: (i % 2) * 3 }; - return () => cy.addWidget(dashboard.id, chart.id, { position }); - }) - ) - .then(widgets => widgetsAssertionFn(widgets, dashboardUrl)); + + const widgets = []; + chartGetters.forEach((chartGetter, i) => { + const position = { autoHeight: false, sizeY: 8, sizeX: 3, col: (i % 2) * 3 }; + cy.get(chartGetter).then(chart => { + widgets.push(cy.addWidget(dashboard.id, chart.id, { position })); + }); + }); + + widgetsAssertionFn(widgets, dashboardUrl); }); } @@ -123,13 +126,11 @@ describe("Chart", () => { .as("queryId"); }); - const charts = []; - it("creates Bar charts", function() { cy.visit(`queries/${this.queryId}/source`); cy.getByTestId("ExecuteButton").click(); - const barChartAssertionFunction = () => { + const getBarChartAssertionFunction = (specificBarChartAssertionFn = () => {}) => () => { // checks for TabbedEditor standard tabs assertTabbedEditor(); @@ -144,23 +145,43 @@ describe("Chart", () => { cy.getByTestId("Chart.ColumnMapping.x").selectAntdOption("Chart.ColumnMapping.x.stage1"); assertPlotPreview("exist"); - // checks for axes default scales and set custom labels - assertAxesAndAddLabels("Stage 1", "Value"); + specificBarChartAssertionFn(); }; - createChartThroughUI("Basic Bar Chart", barChartAssertionFunction).then(basicBarChart => { - charts.push(...Array(8).fill(Cypress.dom.unwrap(basicBarChart))); // temporary, testing behavior for multiple charts + const chartTests = [ + { + name: "Basic Bar Chart", + alias: "basicBarChart", + assertionFn: () => { + assertAxesAndAddLabels("Stage 1", "Value"); + }, + }, + { + name: "Horizontal Bar Chart", + alias: "horizontalBarChart", + assertionFn: () => { + cy.getByTestId("Chart.SwappedAxes").check(); + }, + }, + ]; + // TODO: test other types of bar charts + + chartTests.forEach(({ name, alias, assertionFn }) => { + createChartThroughUI(name, getBarChartAssertionFunction(assertionFn)).as(alias); }); - }); - it("takes a snapshot with different configured Charts", function() { + const chartGetters = chartTests.map(({ alias }) => `@${alias}`); + const withDashboardWidgetsAssertionFn = (widgets, dashboardUrl) => { cy.visit(dashboardUrl); - widgets.forEach(widget => { - cy.getByTestId(getWidgetTestId(widget)).within(() => cy.get("g.points").should("exist")); + widgets.forEach(unfulfilledWidget => { + unfulfilledWidget.then(widget => + cy.getByTestId(getWidgetTestId(widget)).within(() => cy.find("g.points").should("exist")) + ); }); cy.percySnapshot("Visualizations - Charts - Bar"); }; - createDashboardWithCharts("Bar chart visualizations", [...charts], withDashboardWidgetsAssertionFn); + + createDashboardWithCharts("Bar chart visualizations", chartGetters, withDashboardWidgetsAssertionFn); }); }); From bfa874a78cd401b1485998c246f9bca68b460f34 Mon Sep 17 00:00:00 2001 From: Rafael Wendel Date: Sat, 7 Nov 2020 14:51:34 -0300 Subject: [PATCH 05/10] replaced loops with getters for proper workings of cypress --- .../integration/visualizations/chart_spec.js | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/client/cypress/integration/visualizations/chart_spec.js b/client/cypress/integration/visualizations/chart_spec.js index 7ff4b0ac20..d4d43205fc 100644 --- a/client/cypress/integration/visualizations/chart_spec.js +++ b/client/cypress/integration/visualizations/chart_spec.js @@ -1,7 +1,6 @@ /* global cy */ import { getWidgetTestId } from "../../support/dashboard"; -import { get } from "lodash"; const SQL = ` SELECT 'a' AS stage1, 'a1' AS stage2, 11 AS value UNION ALL @@ -106,15 +105,15 @@ function createDashboardWithCharts(title, chartGetters, widgetsAssertionFn = () cy.createDashboard(title).then(dashboard => { const dashboardUrl = `/dashboards/${dashboard.id}`; - const widgets = []; + const widgetGetters = chartGetters.map(chartGetter => `${chartGetter}Widget`); chartGetters.forEach((chartGetter, i) => { const position = { autoHeight: false, sizeY: 8, sizeX: 3, col: (i % 2) * 3 }; - cy.get(chartGetter).then(chart => { - widgets.push(cy.addWidget(dashboard.id, chart.id, { position })); - }); + cy.get(`@${chartGetter}`) + .then(chart => cy.addWidget(dashboard.id, chart.id, { position })) + .as(widgetGetters[i]); }); - widgetsAssertionFn(widgets, dashboardUrl); + widgetsAssertionFn(widgetGetters, dashboardUrl); }); } @@ -170,14 +169,16 @@ describe("Chart", () => { createChartThroughUI(name, getBarChartAssertionFunction(assertionFn)).as(alias); }); - const chartGetters = chartTests.map(({ alias }) => `@${alias}`); + const chartGetters = chartTests.map(({ alias }) => alias); - const withDashboardWidgetsAssertionFn = (widgets, dashboardUrl) => { + const withDashboardWidgetsAssertionFn = (widgetGetters, dashboardUrl) => { cy.visit(dashboardUrl); - widgets.forEach(unfulfilledWidget => { - unfulfilledWidget.then(widget => - cy.getByTestId(getWidgetTestId(widget)).within(() => cy.find("g.points").should("exist")) - ); + widgetGetters.forEach(widgetGetter => { + cy.get(`@${widgetGetter}`).then(widget => { + cy.getByTestId(getWidgetTestId(widget)).within(() => { + cy.get("g.points").should("exist"); + }); + }); }); cy.percySnapshot("Visualizations - Charts - Bar"); }; From 968f1d3eb8d5bc56128daf60367aa986175d62dc Mon Sep 17 00:00:00 2001 From: Rafael Wendel Date: Sat, 7 Nov 2020 15:22:45 -0300 Subject: [PATCH 06/10] added a couple other bar charts --- .../integration/visualizations/chart_spec.js | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/client/cypress/integration/visualizations/chart_spec.js b/client/cypress/integration/visualizations/chart_spec.js index d4d43205fc..96c1a505f8 100644 --- a/client/cypress/integration/visualizations/chart_spec.js +++ b/client/cypress/integration/visualizations/chart_spec.js @@ -104,8 +104,8 @@ function assertAxesAndAddLabels(xaxisLabel, yaxisLabel) { function createDashboardWithCharts(title, chartGetters, widgetsAssertionFn = () => {}) { cy.createDashboard(title).then(dashboard => { const dashboardUrl = `/dashboards/${dashboard.id}`; - const widgetGetters = chartGetters.map(chartGetter => `${chartGetter}Widget`); + chartGetters.forEach((chartGetter, i) => { const position = { autoHeight: false, sizeY: 8, sizeX: 3, col: (i % 2) * 3 }; cy.get(`@${chartGetter}`) @@ -160,10 +160,26 @@ describe("Chart", () => { alias: "horizontalBarChart", assertionFn: () => { cy.getByTestId("Chart.SwappedAxes").check(); + cy.getByTestId("VisualizationEditor.Tabs.XAxis").should("have.text", "Y Axis"); + cy.getByTestId("VisualizationEditor.Tabs.YAxis").should("have.text", "X Axis"); + }, + }, + { + name: "Stacked Bar Chart", + alias: "stackedBarChart", + assertionFn: () => { + // Will not change anything visually: need to set a query that has 2 y columns + cy.getByTestId("Chart.Stacking").selectAntdOption("Chart.Stacking.Stack"); + }, + }, + { + name: "Normalized Bar Chart", + alias: "normalizedBarChart", + assertionFn: () => { + cy.getByTestId("Chart.NormalizeValues").check(); }, }, ]; - // TODO: test other types of bar charts chartTests.forEach(({ name, alias, assertionFn }) => { createChartThroughUI(name, getBarChartAssertionFunction(assertionFn)).as(alias); @@ -180,9 +196,9 @@ describe("Chart", () => { }); }); }); - cy.percySnapshot("Visualizations - Charts - Bar"); }; - + createDashboardWithCharts("Bar chart visualizations", chartGetters, withDashboardWidgetsAssertionFn); + cy.percySnapshot("Visualizations - Charts - Bar"); }); }); From b2e56695754a6ef95433dc0cc82fc6c2ded7118d Mon Sep 17 00:00:00 2001 From: Rafael Wendel Date: Sat, 7 Nov 2020 15:24:45 -0300 Subject: [PATCH 07/10] ran prettier --- client/cypress/integration/visualizations/chart_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cypress/integration/visualizations/chart_spec.js b/client/cypress/integration/visualizations/chart_spec.js index 96c1a505f8..2937e07501 100644 --- a/client/cypress/integration/visualizations/chart_spec.js +++ b/client/cypress/integration/visualizations/chart_spec.js @@ -197,7 +197,7 @@ describe("Chart", () => { }); }); }; - + createDashboardWithCharts("Bar chart visualizations", chartGetters, withDashboardWidgetsAssertionFn); cy.percySnapshot("Visualizations - Charts - Bar"); }); From 38e0a712a530478a3039dcb60abcbd039fb146f7 Mon Sep 17 00:00:00 2001 From: Rafael Wendel Date: Sat, 7 Nov 2020 15:44:44 -0300 Subject: [PATCH 08/10] added a better query for bar charts --- .../integration/visualizations/chart_spec.js | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/client/cypress/integration/visualizations/chart_spec.js b/client/cypress/integration/visualizations/chart_spec.js index 2937e07501..b35bb9438f 100644 --- a/client/cypress/integration/visualizations/chart_spec.js +++ b/client/cypress/integration/visualizations/chart_spec.js @@ -3,17 +3,17 @@ import { getWidgetTestId } from "../../support/dashboard"; const SQL = ` - SELECT 'a' AS stage1, 'a1' AS stage2, 11 AS value UNION ALL - SELECT 'a' AS stage1, 'a2' AS stage2, 12 AS value UNION ALL - SELECT 'a' AS stage1, 'a3' AS stage2, 45 AS value UNION ALL - SELECT 'a' AS stage1, 'a4' AS stage2, 54 AS value UNION ALL - SELECT 'b' AS stage1, 'b1' AS stage2, 33 AS value UNION ALL - SELECT 'b' AS stage1, 'b2' AS stage2, 73 AS value UNION ALL - SELECT 'b' AS stage1, 'b3' AS stage2, 90 AS value UNION ALL - SELECT 'c' AS stage1, 'c1' AS stage2, 19 AS value UNION ALL - SELECT 'c' AS stage1, 'c2' AS stage2, 92 AS value UNION ALL - SELECT 'c' AS stage1, 'c3' AS stage2, 63 AS value UNION ALL - SELECT 'c' AS stage1, 'c4' AS stage2, 44 AS value\ + SELECT 'a' AS stage, 11 AS value1, 22 AS value2 UNION ALL + SELECT 'a' AS stage, 12 AS value1, 41 AS value2 UNION ALL + SELECT 'a' AS stage, 45 AS value1, 93 AS value2 UNION ALL + SELECT 'a' AS stage, 54 AS value1, 79 AS value2 UNION ALL + SELECT 'b' AS stage, 33 AS value1, 65 AS value2 UNION ALL + SELECT 'b' AS stage, 73 AS value1, 50 AS value2 UNION ALL + SELECT 'b' AS stage, 90 AS value1, 40 AS value2 UNION ALL + SELECT 'c' AS stage, 19 AS value1, 33 AS value2 UNION ALL + SELECT 'c' AS stage, 92 AS value1, 14 AS value2 UNION ALL + SELECT 'c' AS stage, 63 AS value1, 65 AS value2 UNION ALL + SELECT 'c' AS stage, 44 AS value1, 27 AS value2\ `; /** @@ -140,8 +140,9 @@ describe("Chart", () => { assertPlotPreview("not.exist"); // creates a chart and checks it is plotted - cy.getByTestId("Chart.ColumnMapping.y").selectAntdOption("Chart.ColumnMapping.y.value"); - cy.getByTestId("Chart.ColumnMapping.x").selectAntdOption("Chart.ColumnMapping.x.stage1"); + cy.getByTestId("Chart.ColumnMapping.x").selectAntdOption("Chart.ColumnMapping.x.stage"); + cy.getByTestId("Chart.ColumnMapping.y").selectAntdOption("Chart.ColumnMapping.y.value1"); + cy.getByTestId("Chart.ColumnMapping.y").selectAntdOption("Chart.ColumnMapping.y.value2"); assertPlotPreview("exist"); specificBarChartAssertionFn(); @@ -152,7 +153,7 @@ describe("Chart", () => { name: "Basic Bar Chart", alias: "basicBarChart", assertionFn: () => { - assertAxesAndAddLabels("Stage 1", "Value"); + assertAxesAndAddLabels("Stage", "Value"); }, }, { From 00417839d2f7d226dd9871f7d9df99694be7f85b Mon Sep 17 00:00:00 2001 From: Rafael Wendel Date: Sat, 7 Nov 2020 15:45:00 -0300 Subject: [PATCH 09/10] removed leftovers --- client/cypress/integration/visualizations/chart_spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/client/cypress/integration/visualizations/chart_spec.js b/client/cypress/integration/visualizations/chart_spec.js index b35bb9438f..6e123a53d5 100644 --- a/client/cypress/integration/visualizations/chart_spec.js +++ b/client/cypress/integration/visualizations/chart_spec.js @@ -169,7 +169,6 @@ describe("Chart", () => { name: "Stacked Bar Chart", alias: "stackedBarChart", assertionFn: () => { - // Will not change anything visually: need to set a query that has 2 y columns cy.getByTestId("Chart.Stacking").selectAntdOption("Chart.Stacking.Stack"); }, }, From 0ab8213b1dbed3fdc74d5132205cdff2339fc1a7 Mon Sep 17 00:00:00 2001 From: Rafael Wendel Date: Tue, 5 Jan 2021 18:34:15 -0300 Subject: [PATCH 10/10] moved helpers to support folder --- .../integration/visualizations/chart_spec.js | 108 ++---------------- .../cypress/support/visualizations/chart.js | 100 ++++++++++++++++ 2 files changed, 107 insertions(+), 101 deletions(-) create mode 100644 client/cypress/support/visualizations/chart.js diff --git a/client/cypress/integration/visualizations/chart_spec.js b/client/cypress/integration/visualizations/chart_spec.js index 6e123a53d5..830023ce56 100644 --- a/client/cypress/integration/visualizations/chart_spec.js +++ b/client/cypress/integration/visualizations/chart_spec.js @@ -1,6 +1,13 @@ /* global cy */ import { getWidgetTestId } from "../../support/dashboard"; +import { + assertAxesAndAddLabels, + assertPlotPreview, + assertTabbedEditor, + createChartThroughUI, + createDashboardWithCharts, +} from "../../support/visualizations/chart"; const SQL = ` SELECT 'a' AS stage, 11 AS value1, 22 AS value2 UNION ALL @@ -16,107 +23,6 @@ const SQL = ` SELECT 'c' AS stage, 44 AS value1, 27 AS value2\ `; -/** - * Asserts the preview canvas exists, then captures the g.points element, which should be generated by plotly and asserts whether it exists - * @param should Passed to should expression after plot points are captured - */ -function assertPlotPreview(should = "exist") { - cy.getByTestId("VisualizationPreview") - .find("g.plot") - .should("exist") - .find("g.points") - .should(should); -} - -function createChartThroughUI(chartName, chartSpecificAssertionFn = () => {}) { - cy.getByTestId("NewVisualization").click(); - cy.getByTestId("VisualizationType").selectAntdOption("VisualizationType.CHART"); - cy.getByTestId("VisualizationName") - .clear() - .type(chartName); - - chartSpecificAssertionFn(); - - cy.server(); - cy.route("POST", "**/api/visualizations").as("SaveVisualization"); - - cy.getByTestId("EditVisualizationDialog") - .contains("button", "Save") - .click(); - - cy.getByTestId("QueryPageVisualizationTabs") - .contains("span", chartName) - .should("exist"); - - cy.wait("@SaveVisualization").should("have.property", "status", 200); - - return cy.get("@SaveVisualization").then(xhr => { - const { id, name, options } = xhr.response.body; - return cy.wrap({ id, name, options }); - }); -} - -function assertTabbedEditor(chartSpecificTabbedEditorAssertionFn = () => {}) { - cy.getByTestId("Chart.GlobalSeriesType").should("exist"); - - cy.getByTestId("VisualizationEditor.Tabs.Series").click(); - cy.getByTestId("VisualizationEditor") - .find("table") - .should("exist"); - - cy.getByTestId("VisualizationEditor.Tabs.Colors").click(); - cy.getByTestId("VisualizationEditor") - .find("table") - .should("exist"); - - cy.getByTestId("VisualizationEditor.Tabs.DataLabels").click(); - cy.getByTestId("VisualizationEditor") - .getByTestId("Chart.DataLabels.ShowDataLabels") - .should("exist"); - - chartSpecificTabbedEditorAssertionFn(); - - cy.getByTestId("VisualizationEditor.Tabs.General").click(); -} - -function assertAxesAndAddLabels(xaxisLabel, yaxisLabel) { - cy.getByTestId("VisualizationEditor.Tabs.XAxis").click(); - cy.getByTestId("Chart.XAxis.Type") - .contains(".ant-select-selection-item", "Auto Detect") - .should("exist"); - - cy.getByTestId("Chart.XAxis.Name") - .clear() - .type(xaxisLabel); - - cy.getByTestId("VisualizationEditor.Tabs.YAxis").click(); - cy.getByTestId("Chart.LeftYAxis.Type") - .contains(".ant-select-selection-item", "Linear") - .should("exist"); - - cy.getByTestId("Chart.LeftYAxis.Name") - .clear() - .type(yaxisLabel); - - cy.getByTestId("VisualizationEditor.Tabs.General").click(); -} - -function createDashboardWithCharts(title, chartGetters, widgetsAssertionFn = () => {}) { - cy.createDashboard(title).then(dashboard => { - const dashboardUrl = `/dashboards/${dashboard.id}`; - const widgetGetters = chartGetters.map(chartGetter => `${chartGetter}Widget`); - - chartGetters.forEach((chartGetter, i) => { - const position = { autoHeight: false, sizeY: 8, sizeX: 3, col: (i % 2) * 3 }; - cy.get(`@${chartGetter}`) - .then(chart => cy.addWidget(dashboard.id, chart.id, { position })) - .as(widgetGetters[i]); - }); - - widgetsAssertionFn(widgetGetters, dashboardUrl); - }); -} - describe("Chart", () => { beforeEach(() => { cy.login(); diff --git a/client/cypress/support/visualizations/chart.js b/client/cypress/support/visualizations/chart.js new file mode 100644 index 0000000000..a18375daee --- /dev/null +++ b/client/cypress/support/visualizations/chart.js @@ -0,0 +1,100 @@ +/** + * Asserts the preview canvas exists, then captures the g.points element, which should be generated by plotly and asserts whether it exists + * @param should Passed to should expression after plot points are captured + */ +export function assertPlotPreview(should = "exist") { + cy.getByTestId("VisualizationPreview") + .find("g.plot") + .should("exist") + .find("g.points") + .should(should); +} + +export function createChartThroughUI(chartName, chartSpecificAssertionFn = () => {}) { + cy.getByTestId("NewVisualization").click(); + cy.getByTestId("VisualizationType").selectAntdOption("VisualizationType.CHART"); + cy.getByTestId("VisualizationName") + .clear() + .type(chartName); + + chartSpecificAssertionFn(); + + cy.server(); + cy.route("POST", "**/api/visualizations").as("SaveVisualization"); + + cy.getByTestId("EditVisualizationDialog") + .contains("button", "Save") + .click(); + + cy.getByTestId("QueryPageVisualizationTabs") + .contains("span", chartName) + .should("exist"); + + cy.wait("@SaveVisualization").should("have.property", "status", 200); + + return cy.get("@SaveVisualization").then(xhr => { + const { id, name, options } = xhr.response.body; + return cy.wrap({ id, name, options }); + }); +} + +export function assertTabbedEditor(chartSpecificTabbedEditorAssertionFn = () => {}) { + cy.getByTestId("Chart.GlobalSeriesType").should("exist"); + + cy.getByTestId("VisualizationEditor.Tabs.Series").click(); + cy.getByTestId("VisualizationEditor") + .find("table") + .should("exist"); + + cy.getByTestId("VisualizationEditor.Tabs.Colors").click(); + cy.getByTestId("VisualizationEditor") + .find("table") + .should("exist"); + + cy.getByTestId("VisualizationEditor.Tabs.DataLabels").click(); + cy.getByTestId("VisualizationEditor") + .getByTestId("Chart.DataLabels.ShowDataLabels") + .should("exist"); + + chartSpecificTabbedEditorAssertionFn(); + + cy.getByTestId("VisualizationEditor.Tabs.General").click(); +} + +export function assertAxesAndAddLabels(xaxisLabel, yaxisLabel) { + cy.getByTestId("VisualizationEditor.Tabs.XAxis").click(); + cy.getByTestId("Chart.XAxis.Type") + .contains(".ant-select-selection-item", "Auto Detect") + .should("exist"); + + cy.getByTestId("Chart.XAxis.Name") + .clear() + .type(xaxisLabel); + + cy.getByTestId("VisualizationEditor.Tabs.YAxis").click(); + cy.getByTestId("Chart.LeftYAxis.Type") + .contains(".ant-select-selection-item", "Linear") + .should("exist"); + + cy.getByTestId("Chart.LeftYAxis.Name") + .clear() + .type(yaxisLabel); + + cy.getByTestId("VisualizationEditor.Tabs.General").click(); +} + +export function createDashboardWithCharts(title, chartGetters, widgetsAssertionFn = () => {}) { + cy.createDashboard(title).then(dashboard => { + const dashboardUrl = `/dashboards/${dashboard.id}`; + const widgetGetters = chartGetters.map(chartGetter => `${chartGetter}Widget`); + + chartGetters.forEach((chartGetter, i) => { + const position = { autoHeight: false, sizeY: 8, sizeX: 3, col: (i % 2) * 3 }; + cy.get(`@${chartGetter}`) + .then(chart => cy.addWidget(dashboard.id, chart.id, { position })) + .as(widgetGetters[i]); + }); + + widgetsAssertionFn(widgetGetters, dashboardUrl); + }); +}