From b5a72e21f73808bcca94341f5a904753a589e67b Mon Sep 17 00:00:00 2001 From: Ross Mabbett <92495987+rtexelm@users.noreply.github.com> Date: Tue, 25 Jun 2024 17:58:26 -0400 Subject: [PATCH] refactor(Homepage): Migrate Home.test to RTL (#29353) --- .../src/pages/Home/Home.test.tsx | 213 +++++++----------- 1 file changed, 85 insertions(+), 128 deletions(-) diff --git a/superset-frontend/src/pages/Home/Home.test.tsx b/superset-frontend/src/pages/Home/Home.test.tsx index 6a63483be55b8..6be4dc186ed79 100644 --- a/superset-frontend/src/pages/Home/Home.test.tsx +++ b/superset-frontend/src/pages/Home/Home.test.tsx @@ -16,23 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -import { styledMount as mount } from 'spec/helpers/theming'; -import { Provider } from 'react-redux'; -import thunk from 'redux-thunk'; import fetchMock from 'fetch-mock'; -import { act } from 'react-dom/test-utils'; -import configureStore from 'redux-mock-store'; import * as uiCore from '@superset-ui/core'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; import Welcome from 'src/pages/Home'; -import { ReactWrapper } from 'enzyme'; -import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; -import { render, screen } from 'spec/helpers/testing-library'; import { getExtensionsRegistry } from '@superset-ui/core'; import setupExtensions from 'src/setup/setupExtensions'; -const mockStore = configureStore([thunk]); -const store = mockStore({}); - const chartsEndpoint = 'glob:*/api/v1/chart/?*'; const chartInfoEndpoint = 'glob:*/api/v1/chart/_info?*'; const chartFavoriteStatusEndpoint = 'glob:*/api/v1/chart/favorite_status?*'; @@ -113,130 +104,104 @@ const mockedProps = { }, }; -describe('Welcome with sql role', () => { - let wrapper: ReactWrapper; +const mockedPropsWithoutSqlRole = { + ...{ + ...mockedProps, + user: { + ...mockedProps.user, + roles: {}, + }, + }, +}; - beforeAll(async () => { - await act(async () => { - wrapper = mount( - - - , - ); - }); - }); +const setupFeatureToggleMock = () => + jest.spyOn(uiCore, 'isFeatureEnabled').mockReturnValue(true); - afterAll(() => { - fetchMock.resetHistory(); +const renderWelcome = (props = mockedProps) => + waitFor(() => { + render(, { + useRedux: true, + useRouter: true, + }); }); - it('renders', () => { - expect(wrapper).toExist(); - }); +afterEach(() => { + fetchMock.resetHistory(); +}); - it('renders all panels on the page on page load', () => { - expect(wrapper.find('CollapsePanel')).toHaveLength(8); - }); +test('With sql role - renders', async () => { + await renderWelcome(); + expect(await screen.findByText('Dashboards')).toBeInTheDocument(); +}); - it('calls api methods in parallel on page load', () => { - const chartCall = fetchMock.calls(/chart\/\?q/); - const savedQueryCall = fetchMock.calls(/saved_query\/\?q/); - const recentCall = fetchMock.calls(/api\/v1\/log\/recent_activity\/*/); - const dashboardCall = fetchMock.calls(/dashboard\/\?q/); - expect(chartCall).toHaveLength(2); - expect(recentCall).toHaveLength(1); - expect(savedQueryCall).toHaveLength(1); - expect(dashboardCall).toHaveLength(2); - }); +test('With sql role - renders all panels on the page on page load', async () => { + await renderWelcome(); + const panels = await screen.findAllByText( + /Dashboards|Charts|Recents|Saved queries/, + ); + expect(panels).toHaveLength(4); }); -describe('Welcome without sql role', () => { - let wrapper: ReactWrapper; - - beforeAll(async () => { - await act(async () => { - const props = { - ...mockedProps, - user: { - ...mockedProps.user, - roles: {}, - }, - }; - wrapper = mount( - - - , - ); - }); - }); +test('With sql role - calls api methods in parallel on page load', async () => { + await renderWelcome(); + expect(fetchMock.calls(chartsEndpoint)).toHaveLength(2); + expect(fetchMock.calls(recentActivityEndpoint)).toHaveLength(1); + expect(fetchMock.calls(savedQueryEndpoint)).toHaveLength(1); + expect(fetchMock.calls(dashboardsEndpoint)).toHaveLength(2); +}); - afterAll(() => { - fetchMock.resetHistory(); - fetchMock.restore(); - }); +test('Without sql role - renders', async () => { + /* + We ignore the ts error here because the type does not recognize the absence of a role entry + */ + // @ts-ignore-next-line + await renderWelcome(mockedPropsWithoutSqlRole); + expect(await screen.findByText('Dashboards')).toBeInTheDocument(); +}); - it('renders', () => { - expect(wrapper).toExist(); - }); +test('Without sql role - renders all panels on the page on page load', async () => { + // @ts-ignore-next-line + await renderWelcome(mockedPropsWithoutSqlRole); + const panels = await screen.findAllByText(/Dashboards|Charts|Recents/); + expect(panels).toHaveLength(3); +}); - it('renders all panels on the page on page load', () => { - expect(wrapper.find('CollapsePanel')).toHaveLength(6); - }); +test('Without sql role - calls api methods in parallel on page load', async () => { + // @ts-ignore-next-line + await renderWelcome(mockedPropsWithoutSqlRole); + expect(fetchMock.calls(chartsEndpoint)).toHaveLength(2); + expect(fetchMock.calls(recentActivityEndpoint)).toHaveLength(1); + expect(fetchMock.calls(savedQueryEndpoint)).toHaveLength(0); + expect(fetchMock.calls(dashboardsEndpoint)).toHaveLength(2); +}); - it('calls api methods in parallel on page load', () => { - const chartCall = fetchMock.calls(/chart\/\?q/); - const savedQueryCall = fetchMock.calls(/saved_query\/\?q/); - const recentCall = fetchMock.calls(/api\/v1\/log\/recent_activity\/*/); - const dashboardCall = fetchMock.calls(/dashboard\/\?q/); - expect(chartCall).toHaveLength(2); - expect(recentCall).toHaveLength(1); - expect(savedQueryCall).toHaveLength(0); - expect(dashboardCall).toHaveLength(2); - }); +// Mock specific to the tests related to the toggle switch +fetchMock.get('glob:*/api/v1/dashboard/*', { + result: { + dashboard_title: 'Dashboard 4', + changed_on_utc: '24 Feb 2014 10:13:14', + url: '/fakeUrl/dashboard/4', + id: '4', + }, }); -async function mountAndWait(props = mockedProps) { - const wrapper = mount( - - - , - ); - await waitForComponentToPaint(wrapper); - return wrapper; -} - -describe('Welcome page with toggle switch', () => { - let wrapper: ReactWrapper; - let isFeatureEnabledMock: any; - - beforeAll(async () => { - isFeatureEnabledMock = jest - .spyOn(uiCore, 'isFeatureEnabled') - .mockReturnValue(true); - await act(async () => { - wrapper = await mountAndWait(); - }); - }); +test('With toggle switch - shows a toggle button when feature flag is turned on', async () => { + setupFeatureToggleMock(); - afterAll(() => { - isFeatureEnabledMock.mockRestore(); - }); + await renderWelcome(); + expect(screen.getByRole('switch')).toBeInTheDocument(); +}); - it('shows a toggle button when feature flags is turned on', async () => { - await waitForComponentToPaint(wrapper); - expect(wrapper.find('Switch')).toExist(); - }); - it('does not show thumbnails when switch is off', async () => { - act(() => { - // @ts-ignore - wrapper.find('button[role="switch"]').props().onClick(); - }); - await waitForComponentToPaint(wrapper); - expect(wrapper.find('ImageLoader')).not.toExist(); - }); +test('With toggle switch - does not show thumbnails when switch is off', async () => { + setupFeatureToggleMock(); + + await renderWelcome(); + const toggle = await screen.findByRole('switch'); + userEvent.click(toggle); + expect(screen.queryByAltText('Thumbnails')).not.toBeInTheDocument(); }); -test('should render an extension component if one is supplied', () => { +test('Should render an extension component if one is supplied', async () => { const extensionsRegistry = getExtensionsRegistry(); extensionsRegistry.set('welcome.banner', () => ( @@ -245,29 +210,21 @@ test('should render an extension component if one is supplied', () => { setupExtensions(); - render( - - - , - ); + await renderWelcome(); expect( screen.getByText('welcome.banner extension component'), ).toBeInTheDocument(); }); -test('should render a submenu extension component if one is supplied', () => { +test('Should render a submenu extension component if one is supplied', async () => { const extensionsRegistry = getExtensionsRegistry(); extensionsRegistry.set('home.submenu', () => <>submenu extension); setupExtensions(); - render( - - - , - ); + await renderWelcome(); expect(screen.getByText('submenu extension')).toBeInTheDocument(); });