-
Nick Fitzpatrick authored
* adding hasMultipleDimensions check to hasLegend clause * Adding queryBuilderMain helper * PR Feedback * remove only
Nick Fitzpatrick authored* adding hasMultipleDimensions check to hasLegend clause * Adding queryBuilderMain helper * PR Feedback * remove only
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
line_chart.cy.spec.js 13.53 KiB
import {
restore,
visitQuestionAdhoc,
popover,
visitDashboard,
openSeriesSettings,
queryBuilderMain,
} from "e2e/support/helpers";
import { SAMPLE_DB_ID } from "e2e/support/cypress_data";
import { SAMPLE_DATABASE } from "e2e/support/cypress_sample_database";
const { ORDERS, ORDERS_ID, PRODUCTS, PRODUCTS_ID } = SAMPLE_DATABASE;
const Y_AXIS_RIGHT_SELECTOR = ".axis.yr";
const testQuery = {
type: "query",
query: {
"source-table": ORDERS_ID,
aggregation: [["count"]],
breakout: [["datetime-field", ["field-id", ORDERS.CREATED_AT], "month"]],
},
database: SAMPLE_DB_ID,
};
describe("scenarios > visualizations > line chart", () => {
beforeEach(() => {
restore();
cy.signInAsNormalUser();
});
it("should be able to change y axis position (metabase#13487)", () => {
visitQuestionAdhoc({
dataset_query: testQuery,
display: "line",
});
cy.findByTestId("viz-settings-button").click();
openSeriesSettings("Count");
cy.findByText("Right").click();
cy.get(Y_AXIS_RIGHT_SELECTOR);
});
it("should be able to format data point values style independently on multi-series chart (metabase#13095)", () => {
visitQuestionAdhoc({
dataset_query: {
type: "query",
query: {
"source-table": ORDERS_ID,
aggregation: [
["sum", ["field", ORDERS.TOTAL, null]],
[
"aggregation-options",
["/", ["avg", ["field", ORDERS.QUANTITY, null]], 10],
{ "display-name": "AvgPct" },
],
],
breakout: [["field", ORDERS.CREATED_AT, { "temporal-unit": "year" }]],
},
database: SAMPLE_DB_ID,
},
display: "line",
visualization_settings: {
"graph.show_values": true,
column_settings: {
'["name","expression"]': { number_style: "percent" },
},
"graph.dimensions": ["CREATED_AT"],
"graph.metrics": ["sum", "expression"],
},
});
cy.get(".value-labels").contains("39.75%");
});
it("should display an error message when there are more series than the chart supports", () => {
visitQuestionAdhoc({
display: "line",
dataset_query: {
database: SAMPLE_DB_ID,
type: "query",
query: {
"source-table": PRODUCTS_ID,
aggregation: [["count"]],
breakout: [
["field", PRODUCTS.CREATED_AT, { "temporal-unit": "year" }],
["field", PRODUCTS.TITLE, null],
],
},
},
visualization_settings: {
"graph.dimensions": ["CREATED_AT", "TITLE"],
"graph.metrics": ["count"],
},
});
cy.findByText(
"This chart type doesn't support more than 100 series of data.",
);
});
it("should correctly display tooltip values when X-axis is numeric and style is 'Ordinal' (metabase#15998)", () => {
visitQuestionAdhoc({
dataset_query: {
database: SAMPLE_DB_ID,
query: {
"source-table": ORDERS_ID,
aggregation: [
["count"],
["sum", ["field", ORDERS.TOTAL, null]],
["avg", ["field", ORDERS.QUANTITY, null]],
],
breakout: [
["field", PRODUCTS.RATING, { "source-field": ORDERS.PRODUCT_ID }],
],
},
type: "query",
},
display: "line",
visualization_settings: {
"graph.x_axis.scale": "ordinal",
"graph.dimensions": ["RATING"],
"graph.metrics": ["count", "sum", "avg"],
},
});
cy.get(".Visualization .enable-dots")
.last()
.find(".dot")
.eq(3)
.trigger("mousemove", { force: true });
popover().within(() => {
testPairedTooltipValues("Product → Rating", "2.7");
testPairedTooltipValues("Count", "191");
testPairedTooltipValues("Sum of Total", "14,747.05");
testPairedTooltipValues("Average of Quantity", "4.3");
});
});
it("should be possible to update/change label for an empty row value (metabase#12128)", () => {
visitQuestionAdhoc({
dataset_query: {
type: "native",
native: {
query:
"SELECT '2020-03-01'::date as date, 'cat1' as category, 23 as \"value\"\nUNION ALL\nSELECT '2020-03-01'::date, '', 44\nUNION ALL\nSELECT '2020-03-01'::date, 'cat3', 58\n\nUNION ALL\n\nSELECT '2020-03-02'::date as date, 'cat1' as category, 20 as \"value\"\nUNION ALL\nSELECT '2020-03-02'::date, '', 50\nUNION ALL\nSELECT '2020-03-02'::date, 'cat3', 58",
"template-tags": {},
},
database: SAMPLE_DB_ID,
},
display: "line",
visualization_settings: {
"graph.dimensions": ["DATE", "CATEGORY"],
"graph.metrics": ["VALUE"],
},
});
cy.findByTestId("viz-settings-button").click();
// Make sure we can update input with some existing value
openSeriesSettings("cat1", true);
popover().within(() => {
cy.findByDisplayValue("cat1").type(" new").blur();
cy.findByDisplayValue("cat1 new");
cy.wait(500);
});
// Now do the same for the input with no value
openSeriesSettings("Unknown", true);
popover().within(() => {
cy.findAllByLabelText("series-name-input").type("cat2").blur();
cy.findByDisplayValue("cat2");
});
cy.button("Done").click();
cy.findAllByTestId("legend-item")
.should("contain", "cat1 new")
.and("contain", "cat2")
.and("contain", "cat3");
});
it("should interpolate null value by not rendering a data point (metabase#4122)", () => {
visitQuestionAdhoc({
dataset_query: {
type: "native",
native: {
query: `
select 'a' x, 1 y
union all
select 'b' x, null y
union all
select 'c' x, 2 y
`,
"template-tags": {},
},
database: SAMPLE_DB_ID,
},
display: "line",
});
cy.get(`.sub._0`).find("circle").should("have.length", 2);
});
describe("tooltip of combined dashboard cards (multi-series) should show the correct column title (metabase#16249", () => {
const RENAMED_FIRST_SERIES = "Foo";
const RENAMED_SECOND_SERIES = "Bar";
it("custom expression names (metabase#16249-1)", () => {
createOrdersQuestionWithAggregation({
name: "16249_Q1",
aggregation: [
[
"aggregation-options",
["sum", ["field", ORDERS.TOTAL, null]],
{ "display-name": "CE" },
],
],
}).then(({ body: { id: question1Id } }) => {
createOrdersQuestionWithAggregation({
name: "16249_Q2",
aggregation: [
[
"aggregation-options",
["avg", ["field", ORDERS.SUBTOTAL, null]],
{ "display-name": "CE" },
],
],
}).then(({ body: { id: question2Id } }) => {
cy.createDashboard().then(({ body: { id: dashboardId } }) => {
addBothSeriesToDashboard({
dashboardId,
firstCardId: question1Id,
secondCardId: question2Id,
});
visitDashboard(dashboardId);
// Rename both series
renameSeries([
["16249_Q1", RENAMED_FIRST_SERIES],
["16249_Q2", RENAMED_SECOND_SERIES],
]);
assertOnLegendItemsValues();
assertOnYAxisValues();
showTooltipForFirstCircleInSeries(0);
popover().within(() => {
testPairedTooltipValues("Created At", "2016");
testPairedTooltipValues(RENAMED_FIRST_SERIES, "42,156.87");
});
showTooltipForFirstCircleInSeries(1);
popover().within(() => {
testPairedTooltipValues("Created At", "2016");
testPairedTooltipValues(RENAMED_SECOND_SERIES, "54.44");
});
});
});
});
});
it("regular column names (metabase#16249-2)", () => {
createOrdersQuestionWithAggregation({
name: "16249_Q3",
aggregation: [["sum", ["field", ORDERS.TOTAL, null]]],
}).then(({ body: { id: question1Id } }) => {
cy.createQuestion({
name: "16249_Q4",
query: {
"source-table": PRODUCTS_ID,
aggregation: [["sum", ["field", PRODUCTS.PRICE, null]]],
breakout: [
["field", PRODUCTS.CREATED_AT, { "temporal-unit": "year" }],
],
},
display: "line",
}).then(({ body: { id: question2Id } }) => {
cy.createDashboard().then(({ body: { id: dashboardId } }) => {
addBothSeriesToDashboard({
dashboardId,
firstCardId: question1Id,
secondCardId: question2Id,
});
visitDashboard(dashboardId);
renameSeries([
["16249_Q3", RENAMED_FIRST_SERIES],
["16249_Q4", RENAMED_SECOND_SERIES],
]);
assertOnLegendItemsValues();
assertOnYAxisValues();
showTooltipForFirstCircleInSeries(0);
popover().within(() => {
testPairedTooltipValues("Created At", "2016");
testPairedTooltipValues(RENAMED_FIRST_SERIES, "42,156.87");
});
showTooltipForFirstCircleInSeries(1);
popover().within(() => {
testPairedTooltipValues("Created At", "2016");
testPairedTooltipValues(RENAMED_SECOND_SERIES, "2,829.03");
});
});
});
});
});
/**
* Helper functions related to repros around 16249 only!
* Note:
* - This might be too abstract and highly specific.
* - That's true in general sense, but that's the reason we're not using them anywhere else than here.
* - Without these abstractions, both tests would be MUCH longer and harder to review.
*/
function addBothSeriesToDashboard({
dashboardId,
firstCardId,
secondCardId,
} = {}) {
// Add the first question to the dashboard
cy.request("POST", `/api/dashboard/${dashboardId}/cards`, {
cardId: firstCardId,
row: 0,
col: 0,
size_x: 18,
size_y: 12,
}).then(({ body: { id: dashCardId } }) => {
// Combine the second question with the first one as the second series
cy.request("PUT", `/api/dashboard/${dashboardId}/cards`, {
cards: [
{
id: dashCardId,
card_id: firstCardId,
row: 0,
col: 0,
size_x: 18,
size_y: 12,
series: [
{
id: secondCardId,
},
],
parameter_mappings: [],
},
],
});
});
}
function createOrdersQuestionWithAggregation({ name, aggregation } = {}) {
return cy.createQuestion({
name,
query: {
"source-table": ORDERS_ID,
aggregation,
breakout: [["field", ORDERS.CREATED_AT, { "temporal-unit": "year" }]],
},
display: "line",
});
}
function renameSeries(series) {
cy.icon("pencil").click();
cy.get(".Card").realHover();
cy.icon("palette").click();
series.forEach(serie => {
const [old_name, new_name] = serie;
cy.findByDisplayValue(old_name).clear().type(new_name);
});
cy.get(".Modal")
.as("modal")
.within(() => {
cy.button("Done").click();
});
cy.button("Save").click();
cy.findByText("You're editing this dashboard.").should("not.exist");
}
function assertOnLegendItemsValues() {
cy.findAllByTestId("legend-item")
.should("contain", RENAMED_FIRST_SERIES)
.and("contain", RENAMED_SECOND_SERIES);
}
function assertOnYAxisValues() {
cy.get(".y-axis-label")
.should("contain", RENAMED_FIRST_SERIES)
.and("contain", RENAMED_SECOND_SERIES);
}
});
describe("problems with the labels when showing only one row in the results (metabase#12782, metabase#4995)", () => {
beforeEach(() => {
visitQuestionAdhoc({
dataset_query: {
database: SAMPLE_DB_ID,
query: {
"source-table": PRODUCTS_ID,
aggregation: [["avg", ["field", PRODUCTS.PRICE, null]]],
breakout: [
["field", PRODUCTS.CREATED_AT, { "temporal-unit": "year" }],
["field", PRODUCTS.CATEGORY, null],
],
filter: ["=", ["field", PRODUCTS.CATEGORY, null], "Doohickey"],
},
type: "query",
},
display: "line",
});
cy.findByText("Category is Doohickey");
});
it("should not drop the chart legend (metabase#4995)", () => {
cy.findAllByTestId("legend-item").should("contain", "Doohickey");
cy.log("Ensure that legend is hidden when not dealing with multi series");
cy.findByTestId("viz-settings-button").click();
cy.findByTestId("remove-CATEGORY").click();
queryBuilderMain().should("not.contain", "Doohickey");
});
it("should display correct axis labels (metabase#12782)", () => {
cy.get(".x-axis-label").invoke("text").should("eq", "Created At");
cy.get(".y-axis-label").invoke("text").should("eq", "Average of Price");
});
});
});
function testPairedTooltipValues(val1, val2) {
cy.contains(val1).closest("td").siblings("td").findByText(val2);
}
function showTooltipForFirstCircleInSeries(series_index) {
cy.get(`.sub._${series_index}`)
.as("firstSeries")
.find("circle")
.first()
.trigger("mousemove", { force: true });
}