From 08e60aa0b3295ddc240f24ec34bfae1f1ee58f41 Mon Sep 17 00:00:00 2001 From: Anton Kulyk <kuliks.anton@gmail.com> Date: Wed, 9 Feb 2022 10:55:43 +0200 Subject: [PATCH] Fix drill actions dispatching redux actions are broken (#20098) * Make `performDefaultAction` usage more readable * Connect `Visualization` to redux * Fix visualization unit tests --- .../components/Visualization.jsx | 13 +++++-- .../components/ChartSettings.unit.spec.js | 22 +++++------ .../components/SmartScalar.unit.spec.js | 10 ++--- .../components/Visualization-pie.unit.spec.js | 26 +++++++++---- .../Visualization-table.unit.spec.js | 4 +- .../components/Visualization.unit.spec.js | 38 +++++++++++-------- .../ChartNestedSettingsSeries.unit.spec.js | 6 +-- 7 files changed, 70 insertions(+), 49 deletions(-) diff --git a/frontend/src/metabase/visualizations/components/Visualization.jsx b/frontend/src/metabase/visualizations/components/Visualization.jsx index 84a38b537cb..0d9d22d6b23 100644 --- a/frontend/src/metabase/visualizations/components/Visualization.jsx +++ b/frontend/src/metabase/visualizations/components/Visualization.jsx @@ -1,5 +1,6 @@ /* eslint-disable react/prop-types */ import React from "react"; +import { connect } from "react-redux"; import ExplicitSize from "metabase/components/ExplicitSize"; import ChartCaption from "metabase/visualizations/components/ChartCaption"; @@ -43,6 +44,7 @@ import { memoize } from "metabase-lib/lib/utils"; // NOTE: pass `CardVisualization` so that we don't include header when providing size to child element @ExplicitSize({ selector: ".CardVisualization" }) +@connect() export default class Visualization extends React.PureComponent { constructor(props) { super(props); @@ -248,12 +250,15 @@ export default class Visualization extends React.PureComponent { return; } - if ( - performDefaultAction(this.getClickActions(clicked), { + const didPerformDefaultAction = performDefaultAction( + this.getClickActions(clicked), + { dispatch: this.props.dispatch, onChangeCardAndRun: this.handleOnChangeCardAndRun, - }) - ) { + }, + ); + + if (didPerformDefaultAction) { return; } diff --git a/frontend/test/metabase/visualizations/components/ChartSettings.unit.spec.js b/frontend/test/metabase/visualizations/components/ChartSettings.unit.spec.js index 5995eddd7ce..a70231a6ee9 100644 --- a/frontend/test/metabase/visualizations/components/ChartSettings.unit.spec.js +++ b/frontend/test/metabase/visualizations/components/ChartSettings.unit.spec.js @@ -1,5 +1,5 @@ import React from "react"; -import { render, fireEvent } from "@testing-library/react"; +import { renderWithProviders, fireEvent } from "__support__/ui"; import ChartSettings from "metabase/visualizations/components/ChartSettings"; @@ -21,10 +21,10 @@ function widget(widget = {}) { describe("ChartSettings", () => { it("should not crash if there are no widgets", () => { - render(<ChartSettings {...DEFAULT_PROPS} widgets={[]} />); + renderWithProviders(<ChartSettings {...DEFAULT_PROPS} widgets={[]} />); }); it("should not crash if the initial section is invalid", () => { - render( + renderWithProviders( <ChartSettings {...DEFAULT_PROPS} widgets={[widget({ section: "Foo" })]} @@ -33,7 +33,7 @@ describe("ChartSettings", () => { ); }); it("should default to the first section (if no section in DEFAULT_TAB_PRIORITY)", () => { - const { getByLabelText } = render( + const { getByLabelText } = renderWithProviders( <ChartSettings {...DEFAULT_PROPS} widgets={[widget({ section: "Foo" }), widget({ section: "Bar" })]} @@ -43,7 +43,7 @@ describe("ChartSettings", () => { expect(getByLabelText("Bar")).not.toBeChecked(); }); it("should default to the DEFAULT_TAB_PRIORITY", () => { - const { getByLabelText } = render( + const { getByLabelText } = renderWithProviders( <ChartSettings {...DEFAULT_PROPS} widgets={[ @@ -56,7 +56,7 @@ describe("ChartSettings", () => { expect(getByLabelText("Display")).toBeChecked(); }); it("should be able to switch sections", () => { - const { getByText, getByLabelText } = render( + const { getByText, getByLabelText } = renderWithProviders( <ChartSettings {...DEFAULT_PROPS} widgets={[widget({ section: "Foo" }), widget({ section: "Bar" })]} @@ -70,7 +70,7 @@ describe("ChartSettings", () => { }); it("should show widget names", () => { - const { getByText } = render( + const { getByText } = renderWithProviders( <ChartSettings {...DEFAULT_PROPS} widgets={[ @@ -84,7 +84,7 @@ describe("ChartSettings", () => { }); it("should not show hidden widgets", () => { - const { getByText, queryByText } = render( + const { getByText, queryByText } = renderWithProviders( <ChartSettings {...DEFAULT_PROPS} widgets={[ @@ -98,7 +98,7 @@ describe("ChartSettings", () => { }); it("should show the section picker if there are multiple sections", () => { - const { getByText } = render( + const { getByText } = renderWithProviders( <ChartSettings {...DEFAULT_PROPS} widgets={[ @@ -111,7 +111,7 @@ describe("ChartSettings", () => { }); it("should not show the section picker if there's only one section", () => { - const { queryByText } = render( + const { queryByText } = renderWithProviders( <ChartSettings {...DEFAULT_PROPS} widgets={[ @@ -130,7 +130,7 @@ describe("ChartSettings", () => { hidden: true, id: "column_settings", }); - const { queryByText } = render( + const { queryByText } = renderWithProviders( <ChartSettings {...DEFAULT_PROPS} widgets={[ diff --git a/frontend/test/metabase/visualizations/components/SmartScalar.unit.spec.js b/frontend/test/metabase/visualizations/components/SmartScalar.unit.spec.js index 9fa4607d7fc..9da208fa1a2 100644 --- a/frontend/test/metabase/visualizations/components/SmartScalar.unit.spec.js +++ b/frontend/test/metabase/visualizations/components/SmartScalar.unit.spec.js @@ -1,5 +1,5 @@ import React from "react"; -import { render } from "@testing-library/react"; +import { renderWithProviders } from "__support__/ui"; import { NumberColumn, DateTimeColumn } from "../__support__/visualizations"; @@ -26,7 +26,7 @@ describe("SmartScalar", () => { col: "Count", }, ]; - const { getAllByText } = render( + const { getAllByText } = renderWithProviders( <Visualization rawSeries={series({ rows, insights })} />, ); getAllByText("120"); @@ -46,7 +46,7 @@ describe("SmartScalar", () => { col: "Count", }, ]; - const { getAllByText } = render( + const { getAllByText } = renderWithProviders( <Visualization rawSeries={series({ rows, insights })} />, ); getAllByText("80"); @@ -66,7 +66,7 @@ describe("SmartScalar", () => { col: "Count", }, ]; - const { getAllByText } = render( + const { getAllByText } = renderWithProviders( <Visualization rawSeries={series({ rows, insights })} />, ); getAllByText("100"); @@ -87,7 +87,7 @@ describe("SmartScalar", () => { col: "Count", }, ]; - const { getAllByText } = render( + const { getAllByText } = renderWithProviders( <Visualization rawSeries={series({ rows, insights })} />, ); getAllByText("8,000%"); diff --git a/frontend/test/metabase/visualizations/components/Visualization-pie.unit.spec.js b/frontend/test/metabase/visualizations/components/Visualization-pie.unit.spec.js index d120a81083a..f7a7b6c6fc7 100644 --- a/frontend/test/metabase/visualizations/components/Visualization-pie.unit.spec.js +++ b/frontend/test/metabase/visualizations/components/Visualization-pie.unit.spec.js @@ -1,5 +1,5 @@ import React from "react"; -import { render, fireEvent } from "@testing-library/react"; +import { renderWithProviders, fireEvent } from "__support__/ui"; import { NumberColumn, StringColumn } from "../__support__/visualizations"; @@ -20,7 +20,9 @@ describe("pie chart", () => { ["bar", 2], ["baz", 2], ]; - const { getAllByText } = render(<Visualization rawSeries={series(rows)} />); + const { getAllByText } = renderWithProviders( + <Visualization rawSeries={series(rows)} />, + ); getAllByText("20%"); getAllByText("40%"); }); @@ -31,7 +33,9 @@ describe("pie chart", () => { ["bar", 0.499], ["baz", 0.001], ]; - const { getAllByText } = render(<Visualization rawSeries={series(rows)} />); + const { getAllByText } = renderWithProviders( + <Visualization rawSeries={series(rows)} />, + ); getAllByText("50.0%"); getAllByText("49.9%"); getAllByText("0.1%"); @@ -44,7 +48,9 @@ describe("pie chart", () => { ["baz", 0.002], ["qux", 0.008], ]; - const { getAllByText } = render(<Visualization rawSeries={series(rows)} />); + const { getAllByText } = renderWithProviders( + <Visualization rawSeries={series(rows)} />, + ); getAllByText("50%"); getAllByText("49%"); getAllByText("1%"); @@ -62,7 +68,9 @@ describe("pie chart", () => { data: { rows: [["foo", 1]], cols }, }, ]; - const { getAllByText } = render(<Visualization rawSeries={series} />); + const { getAllByText } = renderWithProviders( + <Visualization rawSeries={series} />, + ); getAllByText("100%"); // shouldn't multiply legend percent by `scale` getAllByText("123"); // should multiply the count in the center by `scale` }); @@ -85,7 +93,9 @@ describe("pie chart", () => { }, }, ]; - const { getAllByText } = render(<Visualization rawSeries={series} />); + const { getAllByText } = renderWithProviders( + <Visualization rawSeries={series} />, + ); getAllByText("50,1%"); }); @@ -96,7 +106,7 @@ describe("pie chart", () => { ["baz", 0.002], ["qux", 0.008], ]; - const { container, getAllByText, queryAllByText } = render( + const { container, getAllByText, queryAllByText } = renderWithProviders( <Visualization rawSeries={series(rows)} />, ); const paths = container.querySelectorAll("path"); @@ -117,7 +127,7 @@ describe("pie chart", () => { ["bar", 0.49], ["baz", 0.002], ]; - const { container, queryAllByText } = render( + const { container, queryAllByText } = renderWithProviders( <Visualization rawSeries={series(rows)} />, ); const paths = container.querySelectorAll("path"); diff --git a/frontend/test/metabase/visualizations/components/Visualization-table.unit.spec.js b/frontend/test/metabase/visualizations/components/Visualization-table.unit.spec.js index dd83fad7f83..622fbea8cfb 100644 --- a/frontend/test/metabase/visualizations/components/Visualization-table.unit.spec.js +++ b/frontend/test/metabase/visualizations/components/Visualization-table.unit.spec.js @@ -1,5 +1,5 @@ import React from "react"; -import { render } from "@testing-library/react"; +import { renderWithProviders } from "__support__/ui"; import { NumberColumn } from "../__support__/visualizations"; @@ -37,7 +37,7 @@ describe("Table", () => { }, ], }; - const { getByText } = render( + const { getByText } = renderWithProviders( <Visualization rawSeries={series(rows, settings)} />, ); jest.runAllTimers(); diff --git a/frontend/test/metabase/visualizations/components/Visualization.unit.spec.js b/frontend/test/metabase/visualizations/components/Visualization.unit.spec.js index 4ae49dec697..97a9c63ba83 100644 --- a/frontend/test/metabase/visualizations/components/Visualization.unit.spec.js +++ b/frontend/test/metabase/visualizations/components/Visualization.unit.spec.js @@ -1,5 +1,5 @@ import React from "react"; -import ReactDOM from "react-dom"; +import { renderWithProviders } from "__support__/ui"; import { NumberColumn, @@ -16,41 +16,47 @@ import Visualization from "metabase/visualizations/components/Visualization"; describe("Visualization", () => { // eslint-disable-next-line no-unused-vars let element; - const qs = s => element.querySelector(s); - const qsa = s => [...element.querySelectorAll(s)]; const renderViz = async series => { - ReactDOM.render(<Visualization rawSeries={series} />, element); + const utils = renderWithProviders( + <Visualization rawSeries={series} />, + element, + ); // The chart isn't rendered until the next tick. This is due to ExplicitSize // not setting the dimensions until after mounting. await delay(0); + return utils; + }; + + const getBarColors = container => { + const bars = [...container.querySelectorAll(".bar")]; + return bars.map(bar => bar.getAttribute("fill")); }; beforeEach(() => { element = createFixture(); }); + afterEach(() => { - ReactDOM.unmountComponentAtNode(element); cleanupFixture(element); }); describe("scalar", () => { it("should render", async () => { - await renderViz([ + const { container } = await renderViz([ { card: { display: "scalar" }, data: { rows: [[1]], cols: [NumberColumn({ name: "Count" })] }, }, ]); - expect(qs("h1").textContent).toEqual("1"); + expect(container.querySelector("h1").textContent).toEqual("1"); }); }); describe("bar", () => { - const getBarColors = () => qsa(".bar").map(bar => bar.getAttribute("fill")); describe("single series", () => { it("should have correct colors", async () => { - await renderViz([ + const { container } = await renderViz([ { card: { name: "Card", display: "bar" }, data: { @@ -65,7 +71,7 @@ describe("Visualization", () => { }, }, ]); - expect(getBarColors()).toEqual([ + expect(getBarColors(container)).toEqual([ color("brand"), // "count" color("brand"), // "count" ]); @@ -73,7 +79,7 @@ describe("Visualization", () => { }); describe("multiseries: multiple metrics", () => { it("should have correct colors", async () => { - await renderViz([ + const { container } = await renderViz([ { card: { name: "Card", display: "bar" }, data: { @@ -89,7 +95,7 @@ describe("Visualization", () => { }, }, ]); - expect(getBarColors()).toEqual([ + expect(getBarColors(container)).toEqual([ color("brand"), // "count" color("brand"), // "count" color("accent1"), // "sum" @@ -99,7 +105,7 @@ describe("Visualization", () => { }); describe("multiseries: multiple breakouts", () => { it("should have correct colors", async () => { - await renderViz([ + const { container } = await renderViz([ { card: { name: "Card", display: "bar" }, data: { @@ -117,7 +123,7 @@ describe("Visualization", () => { }, }, ]); - expect(getBarColors()).toEqual([ + expect(getBarColors(container)).toEqual([ color("accent1"), // "a" color("accent1"), // "a" color("accent2"), // "b" @@ -127,7 +133,7 @@ describe("Visualization", () => { }); describe("multiseries: dashcard", () => { it("should have correct colors", async () => { - await renderViz([ + const { container } = await renderViz([ { card: { name: "Card1", display: "bar" }, data: { @@ -155,7 +161,7 @@ describe("Visualization", () => { }, }, ]); - expect(getBarColors()).toEqual([ + expect(getBarColors(container)).toEqual([ color("brand"), // "count" color("brand"), // "count" color("accent2"), // "Card2" diff --git a/frontend/test/metabase/visualizations/components/settings/ChartNestedSettingsSeries.unit.spec.js b/frontend/test/metabase/visualizations/components/settings/ChartNestedSettingsSeries.unit.spec.js index 80be9864d64..ed3133581d5 100644 --- a/frontend/test/metabase/visualizations/components/settings/ChartNestedSettingsSeries.unit.spec.js +++ b/frontend/test/metabase/visualizations/components/settings/ChartNestedSettingsSeries.unit.spec.js @@ -1,5 +1,5 @@ import React from "react"; -import { render } from "@testing-library/react"; +import { renderWithProviders } from "__support__/ui"; // these tests use ChartSettings directly, but logic we're testing lives in ChartNestedSettingSeries import ChartSettings from "metabase/visualizations/components/ChartSettings"; @@ -20,7 +20,7 @@ function getSeries(display) { } describe("ChartNestedSettingSeries", () => { it("shouldn't show line/area/bar buttons for row charts", () => { - const { queryByRole } = render( + const { queryByRole } = renderWithProviders( <ChartSettings series={getSeries("row")} initial={{ section: "Display" }} @@ -33,7 +33,7 @@ describe("ChartNestedSettingSeries", () => { }); it("should show line/area/bar buttons for bar charts", () => { - const { getByRole } = render( + const { getByRole } = renderWithProviders( <ChartSettings series={getSeries("bar")} initial={{ section: "Display" }} -- GitLab