diff --git a/frontend/test/metabase/scenarios/binning/qb-explicit-joins.cy.spec.js b/frontend/test/metabase/scenarios/binning/qb-explicit-joins.cy.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..4b87f197f26509ac841bd739ca2f6ed7de1b2d6e --- /dev/null +++ b/frontend/test/metabase/scenarios/binning/qb-explicit-joins.cy.spec.js @@ -0,0 +1,328 @@ +import { restore, popover } from "__support__/e2e/cypress"; +import { SAMPLE_DATASET } from "__support__/e2e/cypress_sample_dataset"; + +const { + ORDERS_ID, + ORDERS, + PEOPLE_ID, + PEOPLE, + PRODUCTS_ID, + PRODUCTS, +} = SAMPLE_DATASET; + +describe("scenarios > binning > from a saved QB question with explicit joins", () => { + beforeEach(() => { + restore(); + cy.signInAsAdmin(); + cy.createQuestion({ + name: "QB Binning", + query: { + "source-table": ORDERS_ID, + joins: [ + { + fields: [ + ["field", PEOPLE.LONGITUDE, { "join-alias": "People" }], + [ + "field", + PEOPLE.BIRTH_DATE, + { "temporal-unit": "default", "join-alias": "People" }, + ], + ], + "source-table": PEOPLE_ID, + condition: [ + "=", + ["field", ORDERS.USER_ID, null], + ["field", PEOPLE.ID, { "join-alias": "People" }], + ], + alias: "People", + }, + { + fields: [["field", PRODUCTS.PRICE, { "join-alias": "Products" }]], + "source-table": PRODUCTS_ID, + condition: [ + "=", + ["field", ORDERS.PRODUCT_ID, null], + ["field", PRODUCTS.ID, { "join-alias": "Products" }], + ], + alias: "Products", + }, + ], + fields: [["field", ORDERS.ID, null]], + }, + }); + + cy.intercept("POST", "/api/dataset").as("dataset"); + }); + + context("via simple question", () => { + beforeEach(() => { + cy.visit("/question/new"); + cy.findByText("Simple question").click(); + cy.findByText("Saved Questions").click(); + cy.findByText("QB Binning").click(); + cy.findByText("Summarize").click(); + cy.wait("@dataset"); + }); + + it("should work for time series", () => { + cy.findByTestId("sidebar-right").within(() => { + openPopoverFromDefaultBucketSize("People → Birth Date", "by month"); + }); + + chooseBucketAndAssert({ + bucketSize: "Year", + columnType: "time", + title: "Count by People → Birth Date: Year", + values: ["1960", "1965", "2000"], + }); + + // Make sure time series footer works as well + cy.get(".AdminSelect-content") + .contains("Year") + .click(); + cy.findByText("Quarter").click(); + + cy.wait("@dataset"); + cy.get(".axis.x").within(() => { + cy.findByText("Q1 - 1960"); + cy.findByText("Q1 - 1965"); + cy.findByText("Q1 - 2000"); + }); + }); + + it("should work for number", () => { + cy.findByTestId("sidebar-right").within(() => { + openPopoverFromDefaultBucketSize("Products → Price", "Auto bin"); + }); + + chooseBucketAndAssert({ + bucketSize: "50 bins", + title: "Count by Products → Price: 50 bins", + values: ["14", "18", "20", "100"], + }); + }); + + it("should work for longitude", () => { + cy.findByTestId("sidebar-right").within(() => { + openPopoverFromDefaultBucketSize("People → Longitude", "Auto bin"); + }); + + chooseBucketAndAssert({ + bucketSize: "Bin every 20 degrees", + title: "Count by People → Longitude: 20°", + values: ["180° W", "160° W", "60° W"], + }); + }); + }); + + context("via custom question", () => { + beforeEach(() => { + cy.visit("/question/new"); + cy.findByText("Custom question").click(); + cy.findByText("Saved Questions").click(); + cy.findByText("QB Binning").click(); + + cy.findByText("Summarize").click(); + cy.findByText("Pick the metric you want to see").click(); + cy.findByText("Count of rows").click(); + cy.findByText("Pick a column to group by").click(); + }); + + it("should work for time series", () => { + popover().within(() => { + openPopoverFromDefaultBucketSize("People → Birth Date", "by month"); + }); + + chooseBucketAndAssert({ + bucketSize: "Year", + columnType: "time", + mode: "notebook", + title: "Count by People → Birth Date: Year", + values: ["1960", "1965", "2000"], + }); + + // Make sure time series footer works as well + cy.get(".AdminSelect-content") + .contains("Year") + .click(); + cy.findByText("Quarter").click(); + + cy.wait("@dataset"); + cy.get(".axis.x").within(() => { + cy.findByText("Q1 - 1960"); + cy.findByText("Q1 - 1965"); + cy.findByText("Q1 - 2000"); + }); + }); + + it("should work for number", () => { + popover().within(() => { + openPopoverFromDefaultBucketSize("Products → Price", "Auto bin"); + }); + + chooseBucketAndAssert({ + bucketSize: "50 bins", + mode: "notebook", + title: "Count by Products → Price: 50 bins", + values: ["14", "18", "20", "100"], + }); + }); + + it("should work for longitude", () => { + popover().within(() => { + openPopoverFromDefaultBucketSize("People → Longitude", "Auto bin"); + }); + + chooseBucketAndAssert({ + bucketSize: "Bin every 20 degrees", + mode: "notebook", + title: "Count by People → Longitude: 20°", + values: ["180° W", "160° W", "60° W"], + }); + }); + }); + + context("via column popover", () => { + beforeEach(() => { + cy.visit("/question/new"); + cy.findByText("Simple question").click(); + cy.findByText("Saved Questions").click(); + cy.findByText("QB Binning").click(); + }); + + /** + * Generated title seems to be incorrect. + * Please see: https://github.com/metabase/metabase/issues/16693. + * + * 1. Todo: unskip the titles in this block once #16693 gets fixed. + */ + it("should work for time series", () => { + cy.findByText("People → Birth Date").click(); + cy.findByText("Distribution").click(); + + /** + * Please see the comment no. 1 above. + */ + // cy.findByText("Count by People → Birth Date: Month"); + + assertOnXYAxisLabels({ xLabel: "People → Birth Date", yLabel: "Count" }); + + cy.findByText("January, 1960"); + cy.findByText("January, 1965"); + + cy.get("circle"); + + // Make sure time series footer works as well + cy.get(".AdminSelect-content") + .contains("Month") + .click(); + cy.findByText("Quarter").click(); + + /** + * Please see the comment no. 1 above. + */ + // cy.findByText("Count by People → Birth Date: Quarter"); + + cy.findByText("Q1 - 1960"); + cy.findByText("Q1 - 1965"); + }); + + it("should work for number", () => { + cy.findByText("Products → Price").click(); + cy.findByText("Distribution").click(); + + /** + * Please see the comment no. 1 above. + */ + // cy.findByText("Count by Products → Price: Auto binned"); + + assertOnXYAxisLabels({ xLabel: "Products → Price", yLabel: "Count" }); + + cy.findByText("12.5"); + cy.findByText("25"); + + cy.get(".bar"); + }); + + it("should work for longitude", () => { + cy.findByText("People → Longitude").click(); + cy.findByText("Distribution").click(); + + /** + * Please see the comment no. 1 above. + */ + // cy.findByText("Count by People → Longitude: Auto binned"); + + assertOnXYAxisLabels({ + xLabel: "People → Longitude", + yLabel: "Count", + }); + + cy.findByText("170° W"); + cy.findByText("160° W"); + + cy.get(".bar"); + }); + }); +}); + +function openPopoverFromDefaultBucketSize(column, bucket) { + cy.findByText(column) + .closest(".List-item") + .should("be.visible") + .as("targetListItem"); + + cy.get("@targetListItem") + .find(".Field-extra") + .as("listItemSelectedBinning") + .should("contain", bucket) + .click(); +} + +function assertOnXYAxisLabels({ xLabel, yLabel } = {}) { + cy.get(".x-axis-label") + .invoke("text") + .should("eq", xLabel); + + cy.get(".y-axis-label") + .invoke("text") + .should("eq", yLabel); +} + +function waitAndAssertOnRequest(requestAlias) { + cy.wait(requestAlias).then(xhr => { + expect(xhr.response.body.error).to.not.exist; + }); +} + +function chooseBucketAndAssert({ + bucketSize, + columnType, + title, + mode = null, + values, +} = {}) { + popover() + .last() + .within(() => { + cy.findByText(bucketSize).click(); + }); + + if (mode === "notebook") { + cy.button("Visualize").click(); + } + + waitAndAssertOnRequest("@dataset"); + + const visualizaitonSelector = columnType === "time" ? "circle" : ".bar"; + cy.get(visualizaitonSelector); + + cy.findByText(title); + + values && + cy.get(".axis.x").within(() => { + values.forEach(value => { + cy.findByText(value); + }); + }); +}