diff --git a/frontend/test/metabase/scenarios/dashboard/chained-filters.cy.spec.js b/frontend/test/metabase/scenarios/dashboard/chained-filters.cy.spec.js index 08af3f8410a24a9020888460f5f9b60bb279d469..289832775a5751ac794ad2443cdacb2d1b788c94 100644 --- a/frontend/test/metabase/scenarios/dashboard/chained-filters.cy.spec.js +++ b/frontend/test/metabase/scenarios/dashboard/chained-filters.cy.spec.js @@ -8,112 +8,6 @@ import { SAMPLE_DATABASE } from "__support__/e2e/cypress_sample_database"; const { PEOPLE, PRODUCTS, PRODUCTS_ID } = SAMPLE_DATABASE; -// This token (simliar to what's done in parameters-embedded.cy.spec.js) just encodes the dashboardId=2 and dashboard parameters -// See this link for details: https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZXNvdXJjZSI6eyJkYXNoYm9hcmQiOjJ9LCJwYXJhbXMiOnt9LCJpYXQiOjE2MDc5NzUwMTMsIl9lbWJlZGRpbmdfcGFyYW1zIjp7InN0YXRlIjoiZW5hYmxlZCIsImNpdHkiOiJlbmFibGVkIn19.nqy_ibysLb6QB9o3loG5SNgOoE5HdexuUjCjA_KS1kM -const DASHBOARD_JWT_TOKEN = - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZXNvdXJjZSI6eyJkYXNoYm9hcmQiOjJ9LCJwYXJhbXMiOnt9LCJpYXQiOjE2MDc5NzUwMTMsIl9lbWJlZGRpbmdfcGFyYW1zIjp7InN0YXRlIjoiZW5hYmxlZCIsImNpdHkiOiJlbmFibGVkIn19.nqy_ibysLb6QB9o3loG5SNgOoE5HdexuUjCjA_KS1kM"; - -// TODO: Refactor `createDashboardWithQuestion`, `createQuestion`, and `createDashboard` into helpers at some point. -// They're also used in `dashboard-drill.cy.spec.js` to help with question setup. -function createDashboardWithQuestion( - { dashboardName = "dashboard" } = {}, - callback, -) { - createQuestion({}, questionId => { - createDashboard({ dashboardName, questionId }, callback); - }); -} - -// Create a native SQL question with two parameters for city and state. -function createQuestion(options, callback) { - cy.createNativeQuestion({ - name: "Count of People by State (SQL)", - native: { - query: - 'SELECT "PUBLIC"."PEOPLE"."STATE" AS "STATE", count(*) AS "count" FROM "PUBLIC"."PEOPLE" WHERE 1=1 [[ AND {{city}}]] [[ AND {{state}}]] GROUP BY "PUBLIC"."PEOPLE"."STATE" ORDER BY "count" DESC, "PUBLIC"."PEOPLE"."STATE" ASC', - "template-tags": { - city: { - id: "6b8b10ef-0104-1047-1e1b-2492d5954555", - name: "city", - "display-name": "City", - type: "dimension", - dimension: ["field", PEOPLE.CITY, null], - "widget-type": "category", - }, - state: { - id: "6b8b10ef-0104-1047-1e1b-2492d5954555", - name: "state", - "display-name": "State", - type: "dimension", - dimension: ["field", PEOPLE.STATE, null], - "widget-type": "category", - }, - }, - }, - display: "bar", - }).then(({ body: { id: questionId } }) => { - callback(questionId); - }); -} - -// Create a dashboard with the city filter dependent on the state filter. -// Once created, add the provided questionId to the dashboard and then -// map the city/state filters to the template-tags in the native query. -function createDashboard({ dashboardName, questionId }, callback) { - cy.createDashboard({ name: dashboardName }).then( - ({ body: { id: dashboardId } }) => { - cy.request("PUT", `/api/dashboard/${dashboardId}`, { - parameters: [ - { - name: "State", - slug: "state", - id: "e8f79be9", - type: "location/state", - }, - { - name: "City", - slug: "city", - id: "170b8e99", - type: "location/city", - filteringParameters: ["e8f79be9"], - }, - ], - }); - - cy.request("POST", `/api/dashboard/${dashboardId}/cards`, { - cardId: questionId, - }).then(({ body: { id: dashCardId } }) => { - cy.request("PUT", `/api/dashboard/${dashboardId}/cards`, { - cards: [ - { - id: dashCardId, - card_id: questionId, - row: 0, - col: 0, - sizeX: 10, - sizeY: 10, - parameter_mappings: [ - { - parameter_id: "e8f79be9", - card_id: questionId, - target: ["dimension", ["template-tag", "state"]], - }, - { - parameter_id: "170b8e99", - card_id: questionId, - target: ["dimension", ["template-tag", "city"]], - }, - ], - }, - ], - }); - - callback(dashboardId); - }); - }, - ); -} - describe("scenarios > dashboard > chained filter", () => { beforeEach(() => { restore(); @@ -241,57 +135,6 @@ describe("scenarios > dashboard > chained filter", () => { }); } - it("can use a chained filter with embedded SQL questions (metabase#13868)", () => { - createDashboardWithQuestion({}, dashboardId => { - // Enable embedding for this dashboard with both the city and state filters enabled - cy.request("PUT", `/api/dashboard/${dashboardId}`, { - embedding_params: { - city: "enabled", - state: "enabled", - }, - enable_embedding: true, - }); - visitDashboard(dashboardId); - }); - - // First make sure normal filtering works - we reuse the chained filter test above. - // Select Alaska as a state. We should see Anchorage as a option but not Anacoco. - // Once Anchorage is selected, the chart should display. - cy.findByText("State").click(); - popover().within(() => { - cy.findByText("AK").click(); - cy.findByText("Add filter").click(); - }); - cy.findByText("City").click(); - popover().within(() => { - cy.findByPlaceholderText("Search by City").type("An"); - cy.findByText("Anacoco").should("not.exist"); - cy.findByText("Anchorage").click(); - cy.findByText("Add filter").click(); - }); - cy.get(".y-label").contains("count"); - - // Then we make sure it works in pseudo-embedded mode. - cy.visit(`/embed/dashboard/${DASHBOARD_JWT_TOKEN}`); - cy.findByText("State").click(); - popover().within(() => { - cy.findByText("AK").click(); - cy.findByText("Add filter").click(); - }); - cy.findByText("City").click(); - popover().within(() => { - cy.findByPlaceholderText("Search by City").type("An"); - cy.findByText("Anacoco").should("not.exist"); - cy.findByText("Anchorage").click(); - cy.findByText("Add filter").click(); - }); - - cy.get(".y-label").contains("count"); - cy.findByText("There was a problem displaying this chart.").should( - "not.exist", - ); - }); - it.skip("should work for all field types (metabase#15170)", () => { // Change Field Types for the following fields cy.request("PUT", `/api/field/${PRODUCTS.ID}`, { diff --git a/frontend/test/metabase/scenarios/embedding/embedding-linked-filters.cy.spec.js b/frontend/test/metabase/scenarios/embedding/embedding-linked-filters.cy.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..583b4f05a0c694c0d2485a45c1849b191640668e --- /dev/null +++ b/frontend/test/metabase/scenarios/embedding/embedding-linked-filters.cy.spec.js @@ -0,0 +1,267 @@ +import { + restore, + visitEmbeddedPage, + filterWidget, + popover, +} from "__support__/e2e/cypress"; + +import { + questionDetails, + dashboardDetails, + mapParameters, +} from "./embedding-linked-filters"; + +describe("scenarios > embedding > dashboard > linked filters (metabase#13639, metabase#13868)", () => { + beforeEach(() => { + restore(); + cy.signInAsAdmin(); + }); + + context("SQL question with field filters", () => { + beforeEach(() => { + cy.createNativeQuestionAndDashboard({ + questionDetails, + dashboardDetails, + }).then(({ body: { id, card_id, dashboard_id } }) => { + cy.wrap(dashboard_id).as("dashboardId"); + + mapParameters({ id, card_id, dashboard_id }); + + // Enable embedding for this dashboard with both the city and state filters enabled + cy.request("PUT", `/api/dashboard/${dashboard_id}`, { + embedding_params: { + city: "enabled", + state: "enabled", + }, + enable_embedding: true, + }); + }); + }); + + it("works when both filters are enabled and their values are set through UI", () => { + cy.get("@dashboardId").then(dashboard_id => { + const payload = { + resource: { dashboard: dashboard_id }, + params: {}, + }; + + visitEmbeddedPage(payload); + }); + cy.findByRole("heading", { name: dashboardDetails.name }); + cy.get(".Card").contains(questionDetails.name); + + cy.get(".bar").should("have.length", 49); + + assertOnXYAxisLabels({ xLabel: "STATE", yLabel: "count" }); + + getXAxisValues() + .should("have.length", 49) + .and("contain", "TX") + .and("contain", "AK"); + + openFilterOptions("State"); + + popover().within(() => { + cy.findByText("AK").click(); + cy.button("Add filter").click(); + }); + + cy.location("search").should("eq", "?state=AK"); + + getXAxisValues() + .should("have.length", 1) + .and("contain", "AK") + .and("not.contain", "TX"); + + cy.get(".bar") + .should("have.length", 1) + .realHover(); + + popover().within(() => { + testPairedTooltipValues("STATE", "AK"); + testPairedTooltipValues("Count", "68"); + }); + + openFilterOptions("City"); + + popover() + .last() + .within(() => { + cy.findByPlaceholderText("Search by City").type("An"); + cy.findByText("Kiana"); + cy.findByText("Anacoco").should("not.exist"); + cy.findByText("Anchorage").click(); + cy.button("Add filter").click(); + }); + + cy.location("search").should("eq", "?state=AK&city=Anchorage"); + + cy.get(".bar") + .should("have.length", 1) + .realHover(); + + popover().within(() => { + testPairedTooltipValues("STATE", "AK"); + testPairedTooltipValues("Count", "1"); + }); + }); + + it("works when main filter's value is set through URL", () => { + cy.get("@dashboardId").then(dashboard_id => { + const payload = { + resource: { dashboard: dashboard_id }, + params: {}, + }; + + visitEmbeddedPage(payload, { + setFilters: "state=AK", + }); + }); + + filterWidget().should("have.length", 2); + + cy.get(".bar") + .should("have.length", 1) + .realHover(); + + popover().within(() => { + testPairedTooltipValues("STATE", "AK"); + testPairedTooltipValues("Count", "68"); + }); + + openFilterOptions("City"); + + popover() + .last() + .within(() => { + cy.findByPlaceholderText("Search by City").type("An"); + cy.findByText("Kiana"); + cy.findByText("Anacoco").should("not.exist"); + cy.findByText("Anchorage").click(); + cy.button("Add filter").click(); + }); + + cy.location("search").should("eq", "?state=AK&city=Anchorage"); + + cy.get(".bar") + .should("have.length", 1) + .realHover(); + + popover().within(() => { + testPairedTooltipValues("STATE", "AK"); + testPairedTooltipValues("Count", "1"); + }); + }); + + it("works when main filter's value is set through URL and when it is hidden at the same time", () => { + cy.get("@dashboardId").then(dashboard_id => { + const payload = { + resource: { dashboard: dashboard_id }, + params: {}, + }; + + visitEmbeddedPage(payload, { + setFilters: "state=AK", + hideFilters: "state", + }); + }); + + cy.get(".bar") + .should("have.length", 1) + .realHover(); + + popover().within(() => { + testPairedTooltipValues("STATE", "AK"); + testPairedTooltipValues("Count", "68"); + }); + + filterWidget() + .should("have.length", 1) + .and("contain", "City") + .click(); + + popover() + .last() + .within(() => { + cy.findByPlaceholderText("Search by City").type("An"); + cy.findByText("Kiana"); + cy.findByText("Anacoco").should("not.exist"); + cy.findByText("Anchorage").click(); + cy.button("Add filter").click(); + }); + + cy.location("search").should("eq", "?state=AK&city=Anchorage"); + + cy.get(".bar") + .should("have.length", 1) + .realHover(); + + popover().within(() => { + testPairedTooltipValues("STATE", "AK"); + testPairedTooltipValues("Count", "1"); + }); + }); + + it("works when main filter is locked", () => { + cy.get("@dashboardId").then(dashboard_id => { + cy.request("PUT", `/api/dashboard/${dashboard_id}`, { + embedding_params: { + city: "enabled", + state: "locked", + }, + }); + + const payload = { + resource: { dashboard: dashboard_id }, + params: { state: ["AK"] }, + }; + + visitEmbeddedPage(payload); + }); + + filterWidget() + .should("have.length", 1) + .and("contain", "City") + .click(); + + popover() + .last() + .within(() => { + cy.findByPlaceholderText("Search by City").type("An"); + cy.findByText("Kiana"); + cy.findByText("Anacoco").should("not.exist"); + cy.findByText("Anchorage").click(); + cy.button("Add filter").click(); + }); + + cy.location("search").should("eq", "?city=Anchorage"); + }); + }); +}); + +function openFilterOptions(name) { + filterWidget() + .contains(name) + .click(); +} + +function testPairedTooltipValues(val1, val2) { + cy.contains(val1) + .closest("td") + .siblings("td") + .findByText(val2); +} + +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 getXAxisValues() { + return cy.get(".axis.x .tick"); +} diff --git a/frontend/test/metabase/scenarios/embedding/embedding-linked-filters.js b/frontend/test/metabase/scenarios/embedding/embedding-linked-filters.js new file mode 100644 index 0000000000000000000000000000000000000000..5bb78c3e320ba9117f9eab8d1d8c7f26b3864d06 --- /dev/null +++ b/frontend/test/metabase/scenarios/embedding/embedding-linked-filters.js @@ -0,0 +1,77 @@ +import { SAMPLE_DATABASE } from "__support__/e2e/cypress_sample_database"; + +const { PEOPLE } = SAMPLE_DATABASE; + +export const questionDetails = { + name: "Count of People by State (SQL)", + native: { + query: + 'SELECT "PUBLIC"."PEOPLE"."STATE" AS "STATE", count(*) AS "count" FROM "PUBLIC"."PEOPLE" WHERE 1=1 [[ AND {{city}}]] [[ AND {{state}}]] GROUP BY "PUBLIC"."PEOPLE"."STATE" ORDER BY "count" DESC, "PUBLIC"."PEOPLE"."STATE" ASC', + "template-tags": { + city: { + id: "6b8b10ef-0104-1047-1e1b-2492d5954555", + name: "city", + "display-name": "City", + type: "dimension", + dimension: ["field", PEOPLE.CITY, null], + "widget-type": "string/=", + }, + state: { + id: "6b8b10ef-0104-1047-1e1b-24s2d5954545", + name: "state", + "display-name": "State", + type: "dimension", + dimension: ["field", PEOPLE.STATE, null], + "widget-type": "string/=", + }, + }, + }, + display: "bar", +}; + +const stateFilter = { + name: "State", + slug: "state", + id: "e8f79be9", + type: "location/state", +}; + +const cityFilter = { + name: "City", + slug: "city", + id: "170b8e99", + type: "location/city", + filteringParameters: [stateFilter.id], +}; + +export const dashboardDetails = { + name: "Embedding Dashboard With Linked Filters", + parameters: [stateFilter, cityFilter], +}; + +export function mapParameters({ id, card_id, dashboard_id } = {}) { + return cy.request("PUT", `/api/dashboard/${dashboard_id}/cards`, { + cards: [ + { + id, + card_id, + row: 0, + col: 0, + sizeX: 18, + sizeY: 10, + parameter_mappings: [ + { + parameter_id: stateFilter.id, + card_id, + target: ["dimension", ["template-tag", stateFilter.slug]], + }, + { + parameter_id: cityFilter.id, + card_id, + target: ["dimension", ["template-tag", cityFilter.slug]], + }, + ], + }, + ], + }); +}