This is an automated email from the ASF dual-hosted git repository. maximebeauchemin pushed a commit to branch knock_enzyme in repository https://gitbox.apache.org/repos/asf/superset.git
commit e10f8be40c1afdcf11228bca6e9d169c0629fb31 Author: Maxime Beauchemin (aider) <[email protected]> AuthorDate: Tue Jan 28 23:33:44 2025 -0800 test: Migrate Dashboard tests from Enzyme to React Testing Library --- .../src/dashboard/components/Dashboard.test.jsx | 133 ++++++++++++++++----- 1 file changed, 103 insertions(+), 30 deletions(-) diff --git a/superset-frontend/src/dashboard/components/Dashboard.test.jsx b/superset-frontend/src/dashboard/components/Dashboard.test.jsx index 60652210ad..5519c96bf2 100644 --- a/superset-frontend/src/dashboard/components/Dashboard.test.jsx +++ b/superset-frontend/src/dashboard/components/Dashboard.test.jsx @@ -16,8 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import { shallow } from 'enzyme'; -import sinon from 'sinon'; +import { render } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; import Dashboard from 'src/dashboard/components/Dashboard'; import { CHART_TYPE } from 'src/dashboard/util/componentTypes'; @@ -66,13 +66,13 @@ describe('Dashboard', () => { const ChildrenComponent = () => <div>Test</div>; - function setup(overrideProps) { - const wrapper = shallow( + function setup(overrideProps = {}) { + const { container } = render( <Dashboard {...props} {...overrideProps}> <ChildrenComponent /> </Dashboard>, ); - return wrapper; + return container; } // activeFilters map use id_column) as key @@ -84,8 +84,8 @@ describe('Dashboard', () => { }; it('should render the children component', () => { - const wrapper = setup(); - expect(wrapper.find(ChildrenComponent)).toExist(); + const container = setup(); + expect(container.querySelector('div')).toHaveTextContent('Test'); }); describe('UNSAFE_componentWillReceiveProps', () => { @@ -95,41 +95,41 @@ describe('Dashboard', () => { }; it('should call addSliceToDashboard if a new slice is added to the layout', () => { - const wrapper = setup(); - const spy = sinon.spy(props.actions, 'addSliceToDashboard'); - wrapper.instance().UNSAFE_componentWillReceiveProps({ + const container = setup(); + const addSliceToDashboardMock = jest.spyOn(props.actions, 'addSliceToDashboard'); + container.firstChild.UNSAFE_componentWillReceiveProps({ ...props, layout: layoutWithExtraChart, }); - spy.restore(); - expect(spy.callCount).toBe(1); + addSliceToDashboardMock.mockRestore(); + expect(addSliceToDashboardMock).toHaveBeenCalledTimes(1); }); it('should call removeSliceFromDashboard if a slice is removed from the layout', () => { - const wrapper = setup({ layout: layoutWithExtraChart }); - const spy = sinon.spy(props.actions, 'removeSliceFromDashboard'); + const container = setup({ layout: layoutWithExtraChart }); + const removeSliceFromDashboardMock = jest.spyOn(props.actions, 'removeSliceFromDashboard'); const nextLayout = { ...layoutWithExtraChart }; delete nextLayout[1001]; - wrapper.instance().UNSAFE_componentWillReceiveProps({ + container.firstChild.UNSAFE_componentWillReceiveProps({ ...props, layout: nextLayout, }); - spy.restore(); - expect(spy.callCount).toBe(1); + removeSliceFromDashboardMock.mockRestore(); + expect(removeSliceFromDashboardMock).toHaveBeenCalledTimes(1); }); }); describe('componentDidUpdate', () => { - let wrapper; + let container; let prevProps; let refreshSpy; beforeEach(() => { - wrapper = setup({ activeFilters: OVERRIDE_FILTERS }); - wrapper.instance().appliedFilters = OVERRIDE_FILTERS; - prevProps = wrapper.instance().props; - refreshSpy = sinon.spy(wrapper.instance(), 'refreshCharts'); + container = setup({ activeFilters: OVERRIDE_FILTERS }); + container.firstChild.appliedFilters = OVERRIDE_FILTERS; + prevProps = container.firstChild.props; + refreshSpy = jest.spyOn(container.firstChild, 'refreshCharts'); }); afterEach(() => { @@ -138,28 +138,101 @@ describe('Dashboard', () => { }); it('should not call refresh when is editMode', () => { - wrapper.setProps({ + render(<Dashboard {...props} activeFilters={OVERRIDE_FILTERS} dashboardState={{ ...dashboardState, editMode: true }} />); + container.firstChild.componentDidUpdate(prevProps); + expect(refreshSpy).not.toHaveBeenCalled(); + }); + + it('should not call refresh when there is no change', () => { + render(<Dashboard {...props} activeFilters={OVERRIDE_FILTERS} />); + container.firstChild.componentDidUpdate(prevProps); + expect(refreshSpy).not.toHaveBeenCalled(); + expect(container.firstChild.appliedFilters).toBe(OVERRIDE_FILTERS); + }); + + it('should call refresh when native filters changed', () => { + getRelatedCharts.mockReturnValue([230]); + render(<Dashboard {...props} activeFilters={{ dashboardState: { ...dashboardState, editMode: true, }, }); - wrapper.instance().componentDidUpdate(prevProps); - expect(refreshSpy.callCount).toBe(0); + container.firstChild.componentDidUpdate(prevProps); + expect(refreshSpy).toHaveBeenCalledTimes(1); }); it('should not call refresh when there is no change', () => { - wrapper.setProps({ + render(<Dashboard {...props} activeFilters={{ activeFilters: OVERRIDE_FILTERS, }); wrapper.instance().componentDidUpdate(prevProps); expect(refreshSpy.callCount).toBe(0); - expect(wrapper.instance().appliedFilters).toBe(OVERRIDE_FILTERS); + expect(container.firstChild.appliedFilters).toEqual({ }); it('should call refresh when native filters changed', () => { getRelatedCharts.mockReturnValue([230]); - wrapper.setProps({ + render(<Dashboard {...props} activeFilters={newFilter} />); + expect(refreshSpy).toHaveBeenCalledTimes(1); + expect(container.firstChild.appliedFilters).toEqual(newFilter); + }); + + it('should call refresh if a filter is removed', () => { + getRelatedCharts.mockReturnValue([]); + render(<Dashboard {...props} activeFilters={{}} />); + expect(refreshSpy).toHaveBeenCalledTimes(1); + expect(container.firstChild.appliedFilters).toEqual({}); + }); + + it('should call refresh if a filter is changed', () => { + getRelatedCharts.mockReturnValue([1]); + const newFilters = { + ...OVERRIDE_FILTERS, + '1_region': { values: ['Canada'], scope: [1] }, + }; + render(<Dashboard {...props} activeFilters={newFilters} />); + expect(refreshSpy).toHaveBeenCalledTimes(1); + expect(container.firstChild.appliedFilters).toEqual(newFilters); + expect(refreshSpy).toHaveBeenCalledWith([1]); + }); + + it('should call refresh with multiple chart ids', () => { + getRelatedCharts.mockReturnValue([1, 2]); + const newFilters = { + ...OVERRIDE_FILTERS, + '2_country_name': { values: ['New Country'], scope: [1, 2] }, + }; + render(<Dashboard {...props} activeFilters={newFilters} />); + expect(refreshSpy).toHaveBeenCalledTimes(1); + expect(container.firstChild.appliedFilters).toEqual(newFilters); + expect(refreshSpy).toHaveBeenCalledWith([1, 2]); + }); + + it('should call refresh if a filter scope is changed', () => { + const newFilters = { + ...OVERRIDE_FILTERS, + '3_country_name': { values: ['USA'], scope: [2] }, + }; + + render(<Dashboard {...props} activeFilters={newFilters} />); + expect(refreshSpy).toHaveBeenCalledTimes(1); + expect(refreshSpy).toHaveBeenCalledWith([2]); + }); + + it('should call refresh with empty [] if a filter is changed but scope is not applicable', () => { + getRelatedCharts.mockReturnValue([]); + const newFilters = { + ...OVERRIDE_FILTERS, + '3_country_name': { values: ['CHINA'], scope: [] }, + }; + + render(<Dashboard {...props} activeFilters={newFilters} />); + expect(refreshSpy).toHaveBeenCalledTimes(1); + expect(refreshSpy).toHaveBeenCalledWith([]); + }); + }); +}); activeFilters: { ...OVERRIDE_FILTERS, ...getAllActiveFilters({ @@ -170,8 +243,8 @@ describe('Dashboard', () => { }, }); wrapper.instance().componentDidUpdate(prevProps); - expect(refreshSpy.callCount).toBe(1); - expect(wrapper.instance().appliedFilters).toEqual({ + expect(refreshSpy).toHaveBeenCalledTimes(1); + expect(container.firstChild.appliedFilters).toEqual({ ...OVERRIDE_FILTERS, [NATIVE_FILTER_ID]: { scope: [230],
