Skip to content
Snippets Groups Projects
Unverified Commit 5e6f526b authored by Nemanja Glumac's avatar Nemanja Glumac Committed by GitHub
Browse files

[E2E] Embedded dashboard with linked filters connected to SQL question (#21520)


* Add data for linked filters needed for the test

* Add coverage for embedding linked filters on SQL question

* Update `widget-type`

Co-authored-by: default avatarflamber <1447303+flamber@users.noreply.github.com>
parent 76d25765
No related branches found
No related tags found
No related merge requests found
......@@ -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}`, {
......
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");
}
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]],
},
],
},
],
});
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment