From 47d4ca3f4159dad08c0936765cf56f3ee92a0377 Mon Sep 17 00:00:00 2001 From: Kenneth Date: Thu, 15 Sep 2022 16:25:00 +0100 Subject: [PATCH 001/133] Migrate addToCartButton tests to RTL --- .../views/addToCartButton.component.test.tsx | 228 +++++++++++------- 1 file changed, 147 insertions(+), 81 deletions(-) diff --git a/packages/datagateway-common/src/views/addToCartButton.component.test.tsx b/packages/datagateway-common/src/views/addToCartButton.component.test.tsx index ea677cb0f..030127195 100644 --- a/packages/datagateway-common/src/views/addToCartButton.component.test.tsx +++ b/packages/datagateway-common/src/views/addToCartButton.component.test.tsx @@ -1,37 +1,33 @@ -import React from 'react'; -import { mount } from 'enzyme'; +import * as React from 'react'; import AddToCartButton, { AddToCartButtonProps, } from './addToCartButton.component'; import configureStore from 'redux-mock-store'; import { initialState as dGCommonInitialState } from '../state/reducers/dgcommon.reducer'; import { StateType } from '../state/app.types'; -import { useCart, useAddToCart, useRemoveFromCart } from '../api/cart'; import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; import { MemoryRouter } from 'react-router-dom'; -import { ReactWrapper } from 'enzyme'; -import { QueryClientProvider, QueryClient } from 'react-query'; - -jest.mock('../api/cart', () => { - const originalModule = jest.requireActual('../api/cart'); - - return { - __esModule: true, - ...originalModule, - useCart: jest.fn(), - useAddToCart: jest.fn(), - useRemoveFromCart: jest.fn(), - }; -}); +import { QueryClient, QueryClientProvider } from 'react-query'; +import axios, { AxiosResponse } from 'axios'; +import { + render, + type RenderResult, + screen, + waitFor, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { UserEvent } from '@testing-library/user-event/setup/setup'; describe('Generic add to cart button', () => { const mockStore = configureStore([thunk]); let state: StateType; + let user: UserEvent; + let holder: HTMLElement; - const createWrapper = (props: AddToCartButtonProps): ReactWrapper => { + function renderComponent(props: AddToCartButtonProps): RenderResult { const store = mockStore(state); - return mount( + return render( @@ -40,9 +36,10 @@ describe('Generic add to cart button', () => { ); - }; + } beforeEach(() => { + user = userEvent.setup(); state = JSON.parse( JSON.stringify({ dgdataview: {}, //Dont need to fill, since not part of the test @@ -52,104 +49,173 @@ describe('Generic add to cart button', () => { }) ); - (useCart as jest.Mock).mockReturnValue({ - data: [], - isLoading: false, - }); - (useAddToCart as jest.Mock).mockReturnValue({ - mutate: jest.fn(), - isLoading: false, - }); - (useRemoveFromCart as jest.Mock).mockReturnValue({ - mutate: jest.fn(), - isLoading: false, - }); + holder = document.createElement('div'); + holder.setAttribute('id', 'datagateway-dataview'); + document.body.appendChild(holder); + + axios.get = jest + .fn() + .mockImplementation((url: string): Promise> => { + if (/.*\/user\/cart\/.*$/.test(url)) { + return Promise.resolve({ + data: { + cartItems: [], + }, + }); + } + return Promise.reject(`Endpoint not mocked: ${url}`); + }); + + axios.post = jest + .fn() + .mockImplementation((url: string): Promise> => { + if (/.*\/user\/cart\/.*\/cartItems/.test(url)) { + return Promise.resolve({ + data: [], + }); + } + return Promise.reject(`Endpoint not mocked: ${url}`); + }); }); afterEach(() => { + document.body.removeChild(holder); jest.clearAllMocks(); }); - it('renders correctly', () => { - const wrapper = createWrapper({ + it('renders correctly', async () => { + renderComponent({ allIds: [1], entityId: 1, entityType: 'investigation', }); - expect(wrapper.find('button').text()).toBe('buttons.add_to_cart'); - expect(wrapper.find('StyledTooltip').prop('title')).toEqual(''); + + expect( + await screen.findByRole('button', { name: 'buttons.add_to_cart' }) + ).toBeInTheDocument(); }); - it('renders as disabled when cart is loading', () => { - (useCart as jest.Mock).mockReturnValue({ - data: undefined, - isLoading: true, - }); - const wrapper = createWrapper({ + it('renders as disabled when cart is loading', async () => { + axios.get = jest.fn().mockReturnValue( + new Promise((_) => { + // never resolve the promise to pretend the query is loading + }) + ); + + renderComponent({ allIds: [1], entityId: 1, entityType: 'investigation', }); - expect(wrapper.find('button').prop('disabled')).toBe(true); - expect(wrapper.find('StyledTooltip').prop('title')).toEqual( - 'buttons.cart_loading_tooltip' - ); + + const addToCartButton = await screen.findByRole('button', { + name: 'buttons.add_to_cart', + }); + + expect(addToCartButton).toBeDisabled(); + + await user.hover(addToCartButton.parentElement); + + expect( + await screen.findByText('buttons.cart_loading_tooltip') + ).toBeInTheDocument(); }); - it('renders as disabled with tooltip when cart does not load', () => { - (useCart as jest.Mock).mockReturnValue({ - data: undefined, - isLoading: false, + it('renders as disabled with tooltip when cart does not load', async () => { + axios.get = jest.fn().mockRejectedValue({ + message: 'Test error message', }); - const wrapper = createWrapper({ + + renderComponent({ allIds: [1], entityId: 1, entityType: 'investigation', }); - expect(wrapper.find('button').prop('disabled')).toBe(true); - expect(wrapper.find('StyledTooltip').prop('title')).toEqual( - 'buttons.cart_loading_failed_tooltip' - ); + + const addToCartButton = await screen.findByRole('button', { + name: 'buttons.add_to_cart', + }); + + expect(addToCartButton).toBeDisabled(); + + await user.hover(addToCartButton.parentElement); + + expect( + await screen.findByText('buttons.cart_loading_failed_tooltip') + ).toBeInTheDocument(); }); - it('calls addToCart action on button press with item not in cart', () => { - const entityType = 'investigation'; - const wrapper = createWrapper({ + it('calls addToCart action on button press with item not in cart', async () => { + renderComponent({ allIds: [1], entityId: 1, - entityType, + entityType: 'investigation', }); - wrapper.find('#add-to-cart-btn-investigation-1').last().simulate('click'); + // wait for data to finish loading + await waitFor(() => { + expect( + screen.getByRole('button', { name: 'buttons.add_to_cart' }) + ).not.toBeDisabled(); + }); + + axios.post = jest.fn().mockResolvedValue({ + data: { + cartItems: [ + { + entityType: 'investigation', + entityId: 1, + }, + ], + }, + }); - expect(useAddToCart).toHaveBeenCalledWith(entityType); + user.click( + await screen.findByRole('button', { name: 'buttons.add_to_cart' }) + ); + + expect( + await screen.findByRole('button', { name: 'buttons.remove_from_cart' }) + ).toBeInTheDocument(); }); - it('calls removeFromCart on button press with item already in cart', () => { - (useCart as jest.Mock).mockReturnValueOnce({ - data: [ - { - entityId: 1, - entityType: 'investigation', - id: 1, - name: 'test', - parentEntities: [], - }, - ], - isLoading: false, + it('calls removeFromCart on button press with item already in cart', async () => { + axios.get = jest.fn().mockResolvedValue({ + data: { + cartItems: [ + { + entityId: 1, + entityType: 'investigation', + id: 1, + name: 'test', + parentEntities: [], + }, + ], + }, }); - const entityType = 'investigation'; - const wrapper = createWrapper({ + renderComponent({ allIds: [1], entityId: 1, - entityType, + entityType: 'investigation', + }); + + expect( + await screen.findByRole('button', { name: 'buttons.remove_from_cart' }) + ).toBeInTheDocument(); + + axios.post = jest.fn().mockResolvedValue({ + data: { + cartItems: [], + }, }); - wrapper - .find('#remove-from-cart-btn-investigation-1') - .last() - .simulate('click'); - expect(useRemoveFromCart).toHaveBeenCalledWith(entityType); + user.click( + screen.getByRole('button', { name: 'buttons.remove_from_cart' }) + ); + + expect( + await screen.findByRole('button', { name: 'buttons.add_to_cart' }) + ).toBeInTheDocument(); }); }); From fcb58b8730d6c64362b861f19cbe3d2ede9ef325 Mon Sep 17 00:00:00 2001 From: Kenneth Date: Thu, 15 Sep 2022 16:36:54 +0100 Subject: [PATCH 002/133] Migrate clearFiltersButton tests to RTL --- .../views/addToCartButton.component.test.tsx | 2 +- .../clearFiltersButton.component.test.tsx | 54 ++++++++----------- 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/packages/datagateway-common/src/views/addToCartButton.component.test.tsx b/packages/datagateway-common/src/views/addToCartButton.component.test.tsx index 030127195..af55f4ecd 100644 --- a/packages/datagateway-common/src/views/addToCartButton.component.test.tsx +++ b/packages/datagateway-common/src/views/addToCartButton.component.test.tsx @@ -210,7 +210,7 @@ describe('Generic add to cart button', () => { }, }); - user.click( + await user.click( screen.getByRole('button', { name: 'buttons.remove_from_cart' }) ); diff --git a/packages/datagateway-common/src/views/clearFiltersButton.component.test.tsx b/packages/datagateway-common/src/views/clearFiltersButton.component.test.tsx index 51e976732..d45be37a6 100644 --- a/packages/datagateway-common/src/views/clearFiltersButton.component.test.tsx +++ b/packages/datagateway-common/src/views/clearFiltersButton.component.test.tsx @@ -1,38 +1,27 @@ -import React from 'react'; +import * as React from 'react'; import configureStore from 'redux-mock-store'; import { initialState as dGCommonInitialState } from '../state/reducers/dgcommon.reducer'; import { StateType } from '../state/app.types'; import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; import { MemoryRouter } from 'react-router-dom'; -import { mount, ReactWrapper } from 'enzyme'; -import { QueryClientProvider, QueryClient } from 'react-query'; +import { QueryClient, QueryClientProvider } from 'react-query'; import ClearFiltersButton, { ClearFilterProps, } from './clearFiltersButton.component'; -import { render, RenderResult } from '@testing-library/react'; +import { render, screen, type RenderResult } from '@testing-library/react'; +import { UserEvent } from '@testing-library/user-event/setup/setup'; +import userEvent from '@testing-library/user-event'; describe('Generic clear filters button', () => { const mockStore = configureStore([thunk]); let state: StateType; let props: ClearFilterProps; + let user: UserEvent; const handleButtonClearFilters = jest.fn(); - const createWrapper = (props: ClearFilterProps): ReactWrapper => { - const store = mockStore(state); - return mount( - - - - - - - - ); - }; - - const createRTLWrapper = (props: ClearFilterProps): RenderResult => { + const renderComponent = (props: ClearFilterProps): RenderResult => { const store = mockStore(state); return render( @@ -47,10 +36,11 @@ describe('Generic clear filters button', () => { beforeEach(() => { props = { - handleButtonClearFilters: handleButtonClearFilters, + handleButtonClearFilters, disabled: false, }; + user = userEvent.setup(); state = JSON.parse( JSON.stringify({ dgdataview: {}, //Dont need to fill, since not part of the test @@ -71,28 +61,28 @@ describe('Generic clear filters button', () => { }); it('renders correctly', () => { - const wrapper = createRTLWrapper(props); - expect(wrapper.asFragment()).toMatchSnapshot(); + const { asFragment } = renderComponent(props); + expect(asFragment()).toMatchSnapshot(); }); - it('calls the handle clear filter button when the button is clicked', () => { - const wrapper = createWrapper(props); + it('calls the handle clear filter button when the button is clicked', async () => { + renderComponent(props); - wrapper - .find('[data-testid="clear-filters-button"]') - .last() - .simulate('click'); + await user.click( + await screen.findByRole('button', { name: 'app.clear_filters' }) + ); expect(handleButtonClearFilters).toHaveBeenCalledTimes(1); }); - it('is disabled when prop disabled is equal to true', () => { - props = { + it('is disabled when prop disabled is equal to true', async () => { + renderComponent({ handleButtonClearFilters: handleButtonClearFilters, disabled: true, - }; - const wrapper = createWrapper(props); + }); - expect(wrapper.find(ClearFiltersButton).props().disabled).toEqual(true); + expect( + await screen.findByRole('button', { name: 'app.clear_filters' }) + ).toBeDisabled(); }); }); From 3086ce4607f84593ac22d32e31ef8a9890891f12 Mon Sep 17 00:00:00 2001 From: Kenneth Date: Fri, 16 Sep 2022 13:41:32 +0100 Subject: [PATCH 003/133] Migrate downloadButton tests to RTL --- .../views/downloadButton.component.test.tsx | 312 +++++++++++------- 1 file changed, 185 insertions(+), 127 deletions(-) diff --git a/packages/datagateway-common/src/views/downloadButton.component.test.tsx b/packages/datagateway-common/src/views/downloadButton.component.test.tsx index 60c2873c4..63bfee915 100644 --- a/packages/datagateway-common/src/views/downloadButton.component.test.tsx +++ b/packages/datagateway-common/src/views/downloadButton.component.test.tsx @@ -1,19 +1,27 @@ -import React from 'react'; -import { mount } from 'enzyme'; +import * as React from 'react'; import DownloadButton, { DownloadButtonProps, } from './downloadButton.component'; import configureStore from 'redux-mock-store'; import { initialState as dGCommonInitialState } from '../state/reducers/dgcommon.reducer'; -import { downloadDatafile } from '../api/datafiles'; -import { downloadDataset } from '../api/datasets'; -import { downloadInvestigation } from '../api/investigations'; +import { + downloadDatafile, + downloadDataset, + downloadInvestigation, +} from '../api'; import { StateType } from '../state/app.types'; import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; import { MemoryRouter } from 'react-router-dom'; -import { ReactWrapper } from 'enzyme'; -import { QueryClientProvider, QueryClient } from 'react-query'; +import { QueryClient, QueryClientProvider } from 'react-query'; +import { + render, + type RenderResult, + screen, + waitFor, +} from '@testing-library/react'; +import { UserEvent } from '@testing-library/user-event/setup/setup'; +import userEvent from '@testing-library/user-event'; jest.mock('../api/datafiles'); jest.mock('../api/datasets'); @@ -22,10 +30,11 @@ jest.mock('../api/investigations'); describe('Generic download button', () => { const mockStore = configureStore([thunk]); let state: StateType; + let user: UserEvent; - const createWrapper = (props: DownloadButtonProps): ReactWrapper => { + function renderComponent(props: DownloadButtonProps): RenderResult { const store = mockStore(state); - return mount( + return render( @@ -34,9 +43,10 @@ describe('Generic download button', () => { ); - }; + } beforeEach(() => { + user = userEvent.setup(); state = JSON.parse( JSON.stringify({ dgdataview: {}, //Dont need to fill, since not part of the test @@ -55,149 +65,197 @@ describe('Generic download button', () => { jest.clearAllMocks(); }); - it('renders correctly', () => { - const props: DownloadButtonProps = { - entityType: 'datafile', - entityName: 'test', - entityId: 1, - entitySize: 1, - }; - const textButtonWrapper = createWrapper(props); - expect(textButtonWrapper.find('button').text()).toBe('buttons.download'); + describe('text variant', () => { + it('renders correctly', async () => { + renderComponent({ + entityType: 'datafile', + entityName: 'test', + entityId: 1, + entitySize: 1, + }); - const iconButtonWrapper = createWrapper({ - ...props, - variant: 'icon', + expect( + await screen.findByRole('button', { name: 'buttons.download' }) + ).toBeInTheDocument(); }); - expect(iconButtonWrapper.find('button').text()).toBe(''); - }); - it('calls download investigation on button press for both text and icon buttons', () => { - const props: DownloadButtonProps = { - entityType: 'investigation', - entityName: 'test', - entityId: 1, - entitySize: 1, - }; - let wrapper = createWrapper(props); - - wrapper.find('#download-btn-1').last().simulate('click'); - expect(downloadInvestigation).toHaveBeenCalledWith( - 'https://www.example.com/ids', - 1, - 'test' - ); + it('calls download investigation on button press', async () => { + renderComponent({ + entityType: 'investigation', + entityName: 'test', + entityId: 1, + entitySize: 1, + }); - jest.clearAllMocks(); + await user.click( + await screen.findByRole('button', { name: 'buttons.download' }) + ); - wrapper = createWrapper({ - ...props, - variant: 'icon', + expect(downloadInvestigation).toHaveBeenCalledWith( + 'https://www.example.com/ids', + 1, + 'test' + ); }); - wrapper.find('#download-btn-1').last().simulate('click'); - expect(downloadInvestigation).toHaveBeenCalledWith( - 'https://www.example.com/ids', - 1, - 'test' - ); - }); + it('calls download dataset on button press', async () => { + renderComponent({ + entityType: 'dataset', + entityName: 'test', + entityId: 1, + entitySize: 1, + }); - it('calls download dataset on button press for both text and icon buttons', () => { - const props: DownloadButtonProps = { - entityType: 'dataset', - entityName: 'test', - entityId: 1, - entitySize: 1, - }; - let wrapper = createWrapper(props); - - wrapper.find('#download-btn-1').last().simulate('click'); - expect(downloadDataset).toHaveBeenCalledWith( - 'https://www.example.com/ids', - 1, - 'test' - ); + await user.click( + await screen.findByRole('button', { name: 'buttons.download' }) + ); - jest.clearAllMocks(); + expect(downloadDataset).toHaveBeenCalledWith( + 'https://www.example.com/ids', + 1, + 'test' + ); + }); + + it('calls download datafile on button press', async () => { + renderComponent({ + entityType: 'datafile', + entityName: 'test', + entityId: 1, + entitySize: 1, + }); + + await user.click( + await screen.findByRole('button', { name: 'buttons.download' }) + ); - wrapper = createWrapper({ - ...props, - variant: 'icon', + expect(downloadDatafile).toHaveBeenCalledWith( + 'https://www.example.com/ids', + 1, + 'test' + ); }); - wrapper.find('#download-btn-1').last().simulate('click'); - expect(downloadDataset).toHaveBeenCalledWith( - 'https://www.example.com/ids', - 1, - 'test' - ); + it('renders a tooltip and disabled button if entity size is zero', async () => { + renderComponent({ + entityType: 'datafile', + entityName: 'test', + entityId: 1, + entitySize: 0, + }); + + const button = await screen.findByRole('button', { + name: 'buttons.download', + }); + + expect(button).toBeDisabled(); + + await user.hover(button.parentElement); + expect( + await screen.findByText('buttons.unable_to_download_tooltip') + ).toBeInTheDocument(); + }); }); - it('calls download datafile on button press for both text and icon buttons', () => { - const props: DownloadButtonProps = { - entityType: 'datafile', - entityName: 'test', - entityId: 1, - entitySize: 1, - }; - let wrapper = createWrapper(props); - - wrapper.find('#download-btn-1').last().simulate('click'); - expect(downloadDatafile).toHaveBeenCalledWith( - 'https://www.example.com/ids', - 1, - 'test' - ); + describe('icon variant', () => { + it('renders icon variant correctly', async () => { + renderComponent({ + entityType: 'datafile', + entityName: 'test', + entityId: 1, + entitySize: 1, + variant: 'icon', + }); - jest.clearAllMocks(); + expect(await screen.findByTestId('GetAppIcon')).toBeInTheDocument(); + }); + + it('calls download investigation on button press', async () => { + renderComponent({ + entityType: 'investigation', + entityName: 'test', + entityId: 1, + entitySize: 1, + variant: 'icon', + }); + + await user.click(await screen.findByTestId('GetAppIcon')); - wrapper = createWrapper({ - ...props, - variant: 'icon', + expect(downloadInvestigation).toHaveBeenCalledWith( + 'https://www.example.com/ids', + 1, + 'test' + ); }); - wrapper.find('#download-btn-1').last().simulate('click'); - expect(downloadDatafile).toHaveBeenCalledWith( - 'https://www.example.com/ids', - 1, - 'test' - ); - }); + it('calls download dataset on button press', async () => { + renderComponent({ + entityType: 'dataset', + entityName: 'test', + entityId: 1, + entitySize: 1, + variant: 'icon', + }); - it('renders nothing when entityName is undefined', () => { - const wrapper = createWrapper({ - entityType: 'datafile', - entityName: undefined, - entityId: 1, - entitySize: 1, + await user.click(await screen.findByTestId('GetAppIcon')); + + expect(downloadDataset).toHaveBeenCalledWith( + 'https://www.example.com/ids', + 1, + 'test' + ); }); - expect(wrapper.find(DownloadButton).children().length).toBe(0); - }); + it('calls download datafile on button press', async () => { + renderComponent({ + entityType: 'datafile', + entityName: 'test', + entityId: 1, + entitySize: 1, + variant: 'icon', + }); - it('renders a tooltip and disabled button if entity size is zero', () => { - const props: DownloadButtonProps = { - entityType: 'datafile', - entityName: 'test', - entityId: 1, - entitySize: 0, - }; - let wrapper = createWrapper(props); + await user.click(await screen.findByTestId('GetAppIcon')); + + expect(downloadDatafile).toHaveBeenCalledWith( + 'https://www.example.com/ids', + 1, + 'test' + ); + }); - expect(wrapper.find('#tooltip-1').first().prop('title')).not.toEqual(''); - wrapper.find('#download-btn-1').last().simulate('click'); - expect(downloadDatafile).not.toHaveBeenCalled(); + it('renders a tooltip and disabled button if entity size is zero', async () => { + renderComponent({ + entityType: 'datafile', + entityName: 'test', + entityId: 1, + entitySize: 0, + variant: 'icon', + }); - jest.clearAllMocks(); + const button = await screen.findByRole('button', { + name: 'buttons.download', + }); - wrapper = createWrapper({ - ...props, - variant: 'icon', + expect(button).toBeDisabled(); + + await user.hover(button.parentElement); + expect( + await screen.findByText('buttons.unable_to_download_tooltip') + ).toBeInTheDocument(); }); + }); - expect(wrapper.find('#tooltip-1').first().prop('title')).not.toEqual(''); - wrapper.find('#download-btn-1').last().simulate('click'); - expect(downloadDatafile).not.toHaveBeenCalled(); + it('renders nothing when entityName is undefined', async () => { + renderComponent({ + entityType: 'datafile', + entityName: undefined, + entityId: 1, + entitySize: 1, + }); + + await waitFor(() => { + expect(screen.queryByRole('button')).toBeNull(); + }); }); }); From 60459b0e36a297a3206151452dadbc8bf5041979 Mon Sep 17 00:00:00 2001 From: Kenneth Date: Fri, 16 Sep 2022 14:37:04 +0100 Subject: [PATCH 004/133] Migrate selectionAlert tests to RTL --- .../views/selectionAlert.component.test.tsx | 191 +++++++++++------- 1 file changed, 113 insertions(+), 78 deletions(-) diff --git a/packages/datagateway-common/src/views/selectionAlert.component.test.tsx b/packages/datagateway-common/src/views/selectionAlert.component.test.tsx index 602c02890..ece6a617a 100644 --- a/packages/datagateway-common/src/views/selectionAlert.component.test.tsx +++ b/packages/datagateway-common/src/views/selectionAlert.component.test.tsx @@ -1,10 +1,11 @@ -import { mount, ReactWrapper } from 'enzyme'; -import React from 'react'; +import * as React from 'react'; import { DownloadCartItem } from '../app.types'; import { NotificationType } from '../state/actions/actions.types'; import SelectionAlert from './selectionAlert.component'; -import { render, RenderResult } from '@testing-library/react'; +import { render, RenderResult, screen, waitFor } from '@testing-library/react'; import { AnyAction } from 'redux'; +import { UserEvent } from '@testing-library/user-event/setup/setup'; +import userEvent from '@testing-library/user-event'; describe('SelectionAlert', () => { let events: CustomEvent[] = []; @@ -34,23 +35,9 @@ describe('SelectionAlert', () => { let storageGetItemMock: jest.Mock; let storageSetItemMock: jest.Mock; let storageRemoveItemMock: jest.Mock; + let user: UserEvent; - const createWrapper = ( - selectedItems: DownloadCartItem[], - loggedInAnonymously: boolean - ): ReactWrapper => { - return mount( - undefined} - width={'100px'} - marginSide={'4px'} - loggedInAnonymously={loggedInAnonymously} - /> - ); - }; - - const createRTLWrapper = ( + const renderComponent = ( selectedItems: DownloadCartItem[], loggedInAnonymously: boolean ): RenderResult => { @@ -66,6 +53,7 @@ describe('SelectionAlert', () => { }; beforeEach(() => { + user = userEvent.setup(); events = []; document.dispatchEvent = (e: Event) => { events.push(e as CustomEvent); @@ -86,43 +74,72 @@ describe('SelectionAlert', () => { }); it('renders correctly', () => { - const wrapper = createRTLWrapper([cartItems[0]], true); - expect(wrapper.asFragment()).toMatchSnapshot(); + const { asFragment } = renderComponent([cartItems[0]], true); + expect(asFragment()).toMatchSnapshot(); }); - it('sends a notification to SciGateway if user is not logged in but only once', () => { - const wrapper = createWrapper([cartItems[0]], true); - - wrapper.update(); - - expect(events.length).toBe(1); - expect(events[0].detail).toEqual({ - type: NotificationType, - payload: { - severity: 'warning', - message: 'selec_alert.warning_message_session_token', - }, + it('sends a notification to SciGateway if user is not logged in but only once', async () => { + const { rerender } = renderComponent([cartItems[0]], true); + + await waitFor(() => { + expect(events.length).toBe(1); + expect(events[0].detail).toEqual({ + type: NotificationType, + payload: { + severity: 'warning', + message: 'selec_alert.warning_message_session_token', + }, + }); + + expect(storageSetItemMock).toHaveBeenCalledTimes(1); + expect(storageSetItemMock).toHaveBeenCalledWith( + 'sentExpiredMessage', + '1' + ); }); - expect(storageSetItemMock).toHaveBeenCalledTimes(1); - expect(storageSetItemMock).toHaveBeenCalledWith('sentExpiredMessage', '1'); - storageGetItemMock.mockReturnValueOnce('1'); - //Adding another element - wrapper.setProps({ selectedItems: [cartItems[0], cartItems[1]] }); + rerender( + undefined} + width={'100px'} + marginSide={'4px'} + /> + ); + expect(events.length).toBe(1); storageGetItemMock.mockReturnValueOnce('1'); + rerender( + undefined} + width={'100px'} + marginSide={'4px'} + /> + ); + //Removing all should reset the message - wrapper.setProps({ selectedItems: [] }); expect(events.length).toBe(1); expect(storageRemoveItemMock).toHaveBeenCalledTimes(1); expect(storageRemoveItemMock).toHaveBeenCalledWith('sentExpiredMessage'); - wrapper.setProps({ selectedItems: [cartItems[0]] }); + rerender( + undefined} + width={'100px'} + marginSide={'4px'} + /> + ); + expect(events.length).toBe(2); expect(events[1].detail).toEqual({ type: NotificationType, @@ -136,72 +153,90 @@ describe('SelectionAlert', () => { it('does not send a notification to SciGateway if user is not logged and it has been sent before', () => { storageGetItemMock.mockReturnValue('1'); - const wrapper = createWrapper([], true); + const { rerender } = renderComponent([], true); - wrapper.update(); + rerender( + undefined} + width={'100px'} + marginSide={'4px'} + /> + ); - //Adding the first element should not broadcast a message - wrapper.setProps({ selectedItems: [cartItems[0]] }); expect(events.length).toBe(0); }); - it('renders correctly with more than one item selected', () => { - const wrapper = createWrapper(cartItems, false); - expect( - wrapper.find('[aria-label="selection-alert-text"]').first().text().trim() - ).toEqual('selec_alert.added'); + it('renders correctly with more than one item selected', async () => { + renderComponent(cartItems, false); + expect(await screen.findByText('selec_alert.added')).toBeInTheDocument(); }); - it('renders correctly with one item removed', () => { - const wrapper = createWrapper(cartItems, false); - wrapper.setProps({ selectedItems: [cartItems[0], cartItems[1]] }); + it('renders correctly with one item removed', async () => { + const { rerender } = renderComponent(cartItems, false); - expect( - wrapper.find('[aria-label="selection-alert-text"]').first().text().trim() - ).toEqual('selec_alert.removed'); + rerender( + undefined} + width={'100px'} + marginSide={'4px'} + /> + ); + + expect(await screen.findByText('selec_alert.removed')).toBeInTheDocument(); }); - it('renders correctly with all items removed', () => { - const wrapper = createWrapper(cartItems, false); - wrapper.setProps({ selectedItems: [] }); + it('renders correctly with all items removed', async () => { + const { rerender } = renderComponent(cartItems, false); + + rerender( + undefined} + width={'100px'} + marginSide={'4px'} + /> + ); - expect( - wrapper.find('[aria-label="selection-alert-text"]').first().text().trim() - ).toEqual('selec_alert.removed'); + expect(await screen.findByText('selec_alert.removed')).toBeInTheDocument(); }); - it('does not render when nothing has changed', () => { - const wrapper = createWrapper([], false); - expect(wrapper.find('[aria-label="selection-alert"]').exists()).toBeFalsy(); + it('does not render when nothing has changed', async () => { + renderComponent([], false); + await waitFor(() => { + expect(screen.queryByLabelText('selection-alert')).toBeNull(); + }); }); - it('does not render when closed', () => { - const wrapper = createWrapper(cartItems, false); - wrapper - .find('[aria-label="selection-alert-close"]') - .last() - .simulate('click'); - wrapper.update(); + it('does not render when closed', async () => { + renderComponent(cartItems, false); - expect(wrapper.find('[aria-label="selection-alert"]').exists()).toBeFalsy(); + await user.click(await screen.findByLabelText('selection-alert-close')); + + await waitFor(() => { + expect(screen.queryByLabelText('selection-alert')).toBeNull(); + }); }); - it('clicking link calls navigateToSelection', () => { + it('clicking link calls navigateToSelection', async () => { let navigated = false; const navigate = (): void => { navigated = true; }; - const wrapper = mount( + + render( ); - wrapper - .find('[aria-label="selection-alert-link"]') - .first() - .simulate('click'); + + await user.click(await screen.findByLabelText('selection-alert-link')); expect(navigated).toBeTruthy(); }); From cee309a742c2a2a02164ade12f1ed9d186167776 Mon Sep 17 00:00:00 2001 From: Kenneth Date: Mon, 26 Sep 2022 14:24:15 +0100 Subject: [PATCH 005/133] Migrate more tests to RTL Powered by kennethnym/autortl ;) --- .../viewCartButton.component.test.tsx.snap | 45 +++++---- .../clearFiltersButton.component.test.tsx | 2 +- .../src/views/viewButton.component.test.tsx | 91 ++++++++----------- .../views/viewCartButton.component.test.tsx | 54 ++++++----- 4 files changed, 96 insertions(+), 96 deletions(-) diff --git a/packages/datagateway-common/src/views/__snapshots__/viewCartButton.component.test.tsx.snap b/packages/datagateway-common/src/views/__snapshots__/viewCartButton.component.test.tsx.snap index a8fd6b380..f3caf9fe4 100644 --- a/packages/datagateway-common/src/views/__snapshots__/viewCartButton.component.test.tsx.snap +++ b/packages/datagateway-common/src/views/__snapshots__/viewCartButton.component.test.tsx.snap @@ -1,21 +1,34 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Generic cart button renders correctly 1`] = ` - - + + `; diff --git a/packages/datagateway-common/src/views/clearFiltersButton.component.test.tsx b/packages/datagateway-common/src/views/clearFiltersButton.component.test.tsx index d45be37a6..0f98d8729 100644 --- a/packages/datagateway-common/src/views/clearFiltersButton.component.test.tsx +++ b/packages/datagateway-common/src/views/clearFiltersButton.component.test.tsx @@ -77,7 +77,7 @@ describe('Generic clear filters button', () => { it('is disabled when prop disabled is equal to true', async () => { renderComponent({ - handleButtonClearFilters: handleButtonClearFilters, + handleButtonClearFilters, disabled: true, }); diff --git a/packages/datagateway-common/src/views/viewButton.component.test.tsx b/packages/datagateway-common/src/views/viewButton.component.test.tsx index c7fd0f1db..05a1d1558 100644 --- a/packages/datagateway-common/src/views/viewButton.component.test.tsx +++ b/packages/datagateway-common/src/views/viewButton.component.test.tsx @@ -1,58 +1,54 @@ -import React from 'react'; +import { render, screen, type RenderResult } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import type { UserEvent } from '@testing-library/user-event/setup/setup'; +import * as React from 'react'; import configureStore from 'redux-mock-store'; import { initialState as dGCommonInitialState } from '../state/reducers/dgcommon.reducer'; import { StateType } from '../state/app.types'; import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; import { MemoryRouter } from 'react-router-dom'; -import { mount, ReactWrapper } from 'enzyme'; import { QueryClientProvider, QueryClient } from 'react-query'; import ViewButton, { ViewProps } from './viewButton.component'; -import { render, RenderResult } from '@testing-library/react'; describe('Generic view button', () => { const mockStore = configureStore([thunk]); + const handleButtonChange = jest.fn(); + let user: UserEvent; let state: StateType; let props: ViewProps; - const handleButtonChange = jest.fn(); - - const createWrapper = (props: ViewProps): ReactWrapper => { - const store = mockStore(state); - return mount( - - - - - - - - ); - }; - - const createRTLWrapper = (props: ViewProps): RenderResult => { + function renderComponent(props: ViewProps): RenderResult { const store = mockStore(state); return render( - + ); - }; + } beforeEach(() => { + user = userEvent.setup(); props = { viewCards: true, handleButtonChange: handleButtonChange, disabled: false, }; - state = JSON.parse( JSON.stringify({ - dgdataview: {}, //Dont need to fill, since not part of the test + dgdataview: {}, + //Dont need to fill, since not part of the test dgcommon: { ...dGCommonInitialState, urls: { @@ -69,47 +65,32 @@ describe('Generic view button', () => { handleButtonChange.mockClear(); }); - it('renders correctly', () => { - const wrapper = createRTLWrapper(props); - expect(wrapper.asFragment()).toMatchSnapshot(); + it('renders correctly', async () => { + const { asFragment } = renderComponent(props); + expect(asFragment()).toMatchSnapshot(); }); - it('calls the handle button change when the view button is clicked', () => { - const wrapper = createWrapper(props); - - wrapper - .find('[aria-label="page view app.view_table"]') - .last() - .simulate('click'); - + it('calls the handle button change when the view button is clicked', async () => { + renderComponent(props); + await user.click( + await screen.findByRole('button', { + name: 'page view app.view_table', + }) + ); expect(handleButtonChange).toHaveBeenCalledTimes(1); - - wrapper.update(); - - expect( - wrapper.find('[aria-label="page view app.view_cards"]') - ).toBeTruthy(); - - wrapper - .find('[aria-label="page view app.view_table"]') - .last() - .simulate('click'); - - expect(handleButtonChange).toHaveBeenCalledTimes(2); - - expect( - wrapper.find('[aria-label="page view app.view_cards"]') - ).toBeTruthy(); }); - it('is disabled when prop disabled is equal to true', () => { + it('is disabled when prop disabled is equal to true', async () => { props = { viewCards: true, handleButtonChange: handleButtonChange, disabled: true, }; - const wrapper = createWrapper(props); - - expect(wrapper.find(ViewButton).props().disabled).toEqual(true); + renderComponent(props); + expect( + await screen.findByRole('button', { + name: 'page view app.view_table', + }) + ).toBeDisabled(); }); }); diff --git a/packages/datagateway-common/src/views/viewCartButton.component.test.tsx b/packages/datagateway-common/src/views/viewCartButton.component.test.tsx index 70a543b34..9eeee6ef4 100644 --- a/packages/datagateway-common/src/views/viewCartButton.component.test.tsx +++ b/packages/datagateway-common/src/views/viewCartButton.component.test.tsx @@ -1,44 +1,53 @@ -import React from 'react'; +import { render, type RenderResult, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import type { UserEvent } from '@testing-library/user-event/setup/setup'; +import * as React from 'react'; import configureStore from 'redux-mock-store'; import { initialState as dGCommonInitialState } from '../state/reducers/dgcommon.reducer'; import { StateType } from '../state/app.types'; import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; import { MemoryRouter } from 'react-router-dom'; -import { mount, ReactWrapper, shallow } from 'enzyme'; -import { QueryClientProvider, QueryClient } from 'react-query'; +import { QueryClient, QueryClientProvider } from 'react-query'; import ViewCartButton, { CartProps } from './viewCartButton.component'; -import { Badge } from '@mui/material'; describe('Generic cart button', () => { const mockStore = configureStore([thunk]); + const navigateToDownload = jest.fn(); + let user: UserEvent; let state: StateType; let props: CartProps; - const navigateToDownload = jest.fn(); - - const createWrapper = (props: CartProps): ReactWrapper => { + function renderComponent(props: CartProps): RenderResult { const store = mockStore(state); - return mount( + return render( - + ); - }; + } beforeEach(() => { + user = userEvent.setup(); props = { cartItems: [], navigateToDownload: navigateToDownload, }; - state = JSON.parse( JSON.stringify({ - dgdataview: {}, //Dont need to fill, since not part of the test + dgdataview: {}, + //Dont need to fill, since not part of the test dgcommon: { ...dGCommonInitialState, urls: { @@ -55,20 +64,18 @@ describe('Generic cart button', () => { navigateToDownload.mockClear(); }); - it('renders correctly', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); + it('renders correctly', async () => { + const { asFragment } = render(); + expect(asFragment()).toMatchSnapshot(); }); - it('calls the navigate to download plugin when the cart clicked', () => { - const wrapper = createWrapper(props); - - wrapper.find('[aria-label="app.cart_arialabel"]').last().simulate('click'); - + it('calls the navigate to download plugin when the cart clicked', async () => { + renderComponent(props); + await user.click(await screen.findByLabelText('app.cart_arialabel')); expect(navigateToDownload).toHaveBeenCalledTimes(1); }); - it('has cartItems', () => { + it('has cartItems', async () => { props = { cartItems: [ { @@ -88,8 +95,7 @@ describe('Generic cart button', () => { ], navigateToDownload: navigateToDownload, }; - const wrapper = createWrapper(props); - - expect(wrapper.find(Badge).props().badgeContent).toEqual(2); + renderComponent(props); + expect(await screen.findByText('2')).toBeInTheDocument(); }); }); From 5f66366553f711edb17ae53106ef1ccb310e92f1 Mon Sep 17 00:00:00 2001 From: Kenneth Date: Mon, 26 Sep 2022 14:39:13 +0100 Subject: [PATCH 006/133] Migrate actionCell test to RTL --- .../actionCell.component.test.tsx.snap | 31 +++++++++---------- .../actionCell.component.test.tsx | 18 ++++++----- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/packages/datagateway-common/src/table/cellRenderers/__snapshots__/actionCell.component.test.tsx.snap b/packages/datagateway-common/src/table/cellRenderers/__snapshots__/actionCell.component.test.tsx.snap index 7d4d43b2f..116823ebe 100644 --- a/packages/datagateway-common/src/table/cellRenderers/__snapshots__/actionCell.component.test.tsx.snap +++ b/packages/datagateway-common/src/table/cellRenderers/__snapshots__/actionCell.component.test.tsx.snap @@ -1,24 +1,21 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Action cell component renders an action correctly 1`] = ` - - - + +
+

+ Rendered an action using test! +

+
+
`; exports[`Action cell component renders no actions correctly 1`] = ` - + +
+ `; diff --git a/packages/datagateway-common/src/table/cellRenderers/actionCell.component.test.tsx b/packages/datagateway-common/src/table/cellRenderers/actionCell.component.test.tsx index 014426cfc..a44943d73 100644 --- a/packages/datagateway-common/src/table/cellRenderers/actionCell.component.test.tsx +++ b/packages/datagateway-common/src/table/cellRenderers/actionCell.component.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { shallow } from 'enzyme'; +import { render } from '@testing-library/react'; +import * as React from 'react'; import ActionCell from './actionCell.component'; import { TableActionProps } from '../table.component'; @@ -13,13 +13,15 @@ describe('Action cell component', () => { className: 'test-class', }; - it('renders no actions correctly', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); + it('renders no actions correctly', async () => { + const { asFragment } = render( + + ); + expect(asFragment()).toMatchSnapshot(); }); - it('renders an action correctly', () => { - const wrapper = shallow( + it('renders an action correctly', async () => { + const { asFragment } = render( { ]} /> ); - expect(wrapper).toMatchSnapshot(); + expect(asFragment()).toMatchSnapshot(); }); }); From df27d8a2faa1cb0c8dfa3664ec3789ef68657fe9 Mon Sep 17 00:00:00 2001 From: Kenneth Date: Mon, 26 Sep 2022 14:44:24 +0100 Subject: [PATCH 007/133] Migrate dataCell test to RTL --- .../dataCell.component.test.tsx.snap | 162 ++++++------------ 1 file changed, 48 insertions(+), 114 deletions(-) diff --git a/packages/datagateway-common/src/table/cellRenderers/__snapshots__/dataCell.component.test.tsx.snap b/packages/datagateway-common/src/table/cellRenderers/__snapshots__/dataCell.component.test.tsx.snap index 95b6cf378..09d9b1061 100644 --- a/packages/datagateway-common/src/table/cellRenderers/__snapshots__/dataCell.component.test.tsx.snap +++ b/packages/datagateway-common/src/table/cellRenderers/__snapshots__/dataCell.component.test.tsx.snap @@ -1,138 +1,72 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Data cell component renders correctly 1`] = ` - - +
- non nested property - - -
- +

+
+
+
- + `; exports[`Data cell component renders nested cell data correctly 1`] = ` - - +
- nested property - - -
- +

+
+
+
- + `; exports[`Data cell component renders provided cell data correctly 1`] = ` - - +
- provided test - - -
- +

+
+
+
- + `; From c297f8e0984839a17f3a19a68806fb3f423db68e Mon Sep 17 00:00:00 2001 From: Kenneth Date: Mon, 26 Sep 2022 15:01:36 +0100 Subject: [PATCH 008/133] Migrate expandCell test to RTL --- .../expandCell.component.test.tsx.snap | 79 ++++++++++++------- .../expandCell.component.test.tsx | 41 ++++++---- 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/packages/datagateway-common/src/table/cellRenderers/__snapshots__/expandCell.component.test.tsx.snap b/packages/datagateway-common/src/table/cellRenderers/__snapshots__/expandCell.component.test.tsx.snap index 6265c2ecf..ab35deda1 100644 --- a/packages/datagateway-common/src/table/cellRenderers/__snapshots__/expandCell.component.test.tsx.snap +++ b/packages/datagateway-common/src/table/cellRenderers/__snapshots__/expandCell.component.test.tsx.snap @@ -1,36 +1,61 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Expand cell component renders correctly when expanded 1`] = ` - - +
- - - + +
+ `; exports[`Expand cell component renders correctly when not expanded 1`] = ` - - +
- - - + +
+ `; diff --git a/packages/datagateway-common/src/table/cellRenderers/expandCell.component.test.tsx b/packages/datagateway-common/src/table/cellRenderers/expandCell.component.test.tsx index e7be5932c..860030baa 100644 --- a/packages/datagateway-common/src/table/cellRenderers/expandCell.component.test.tsx +++ b/packages/datagateway-common/src/table/cellRenderers/expandCell.component.test.tsx @@ -1,8 +1,11 @@ -import React from 'react'; -import { shallow } from 'enzyme'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import type { UserEvent } from '@testing-library/user-event/setup/setup'; +import * as React from 'react'; import ExpandCell from './expandCell.component'; describe('Expand cell component', () => { + let user: UserEvent; const setExpandedIndex = jest.fn(); const expandCellProps = { columnIndex: 1, @@ -14,35 +17,39 @@ describe('Expand cell component', () => { setExpandedIndex, }; + beforeEach(() => { + user = userEvent.setup(); + }); + afterEach(() => { setExpandedIndex.mockClear(); }); - it('renders correctly when expanded', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); + it('renders correctly when expanded', async () => { + const { asFragment } = render(); + expect(asFragment()).toMatchSnapshot(); }); - it('sets the expanded index to -1 when ExpandLess button is pressed', () => { - const wrapper = shallow(); - - wrapper.childAt(0).prop('onClick')(); + it('sets the expanded index to -1 when ExpandLess button is pressed', async () => { + render(); + await user.click( + await screen.findByRole('button', { name: 'Hide details' }) + ); expect(setExpandedIndex).toHaveBeenCalledWith(-1); }); - it('renders correctly when not expanded', () => { - const wrapper = shallow( + it('renders correctly when not expanded', async () => { + const { asFragment } = render( ); - expect(wrapper).toMatchSnapshot(); + expect(asFragment()).toMatchSnapshot(); }); - it('sets the expanded index to rowIndex when ExpandMore button is pressed', () => { - const wrapper = shallow( - + it('sets the expanded index to rowIndex when ExpandMore button is pressed', async () => { + render(); + await user.click( + await screen.findByRole('button', { name: 'Show details' }) ); - - wrapper.childAt(0).prop('onClick')(); expect(setExpandedIndex).toHaveBeenCalledWith(expandCellProps.rowIndex); }); }); From a89c29bb151f5aff4bbeccad47faebc4a95caa9e Mon Sep 17 00:00:00 2001 From: Kenneth Date: Tue, 27 Sep 2022 12:12:29 +0100 Subject: [PATCH 009/133] Migrate dateColumnFilter test to RTL --- .../dateColumnFilter.component.test.tsx.snap | 476 +++++++----------- .../dateColumnFilter.component.test.tsx | 442 ++++++++-------- 2 files changed, 426 insertions(+), 492 deletions(-) diff --git a/packages/datagateway-common/src/table/columnFilters/__snapshots__/dateColumnFilter.component.test.tsx.snap b/packages/datagateway-common/src/table/columnFilters/__snapshots__/dateColumnFilter.component.test.tsx.snap index 6cdf309c3..6ddf123f7 100644 --- a/packages/datagateway-common/src/table/columnFilters/__snapshots__/dateColumnFilter.component.test.tsx.snap +++ b/packages/datagateway-common/src/table/columnFilters/__snapshots__/dateColumnFilter.component.test.tsx.snap @@ -1,303 +1,199 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Date filter component CustomClearButton renders correctly 1`] = ` - - Clear - -`; - -exports[`Date filter component DatePicker functionality useTextFilter hook returns a function which can generate a working text filter 1`] = ` -
- + + `; -exports[`Date filter component DateTimePicker functionality useTextFilter hook returns a function which can generate a working text filter 1`] = ` -
- -