diff --git a/src/domains/helpers/EditDomainRedirectsModal.tsx b/src/domains/helpers/EditDomainRedirectsModal.tsx index 2706a210..0bc86bf8 100644 --- a/src/domains/helpers/EditDomainRedirectsModal.tsx +++ b/src/domains/helpers/EditDomainRedirectsModal.tsx @@ -38,7 +38,7 @@ export const EditDomainRedirectsModal: FC = ( return ( -
+ Edit redirects for {domain.domain} diff --git a/src/servers/ServersDropdown.tsx b/src/servers/ServersDropdown.tsx index cf619228..e549471a 100644 --- a/src/servers/ServersDropdown.tsx +++ b/src/servers/ServersDropdown.tsx @@ -10,7 +10,7 @@ export interface ServersDropdownProps { selectedServer: SelectedServer; } -const ServersDropdown = ({ servers, selectedServer }: ServersDropdownProps) => { +export const ServersDropdown = ({ servers, selectedServer }: ServersDropdownProps) => { const serversList = values(servers); const renderServers = () => { @@ -46,5 +46,3 @@ const ServersDropdown = ({ servers, selectedServer }: ServersDropdownProps) => { ); }; - -export default ServersDropdown; diff --git a/src/servers/services/provideServices.ts b/src/servers/services/provideServices.ts index fcb04a46..9f177cb6 100644 --- a/src/servers/services/provideServices.ts +++ b/src/servers/services/provideServices.ts @@ -1,6 +1,6 @@ import Bottle from 'bottlejs'; import CreateServer from '../CreateServer'; -import ServersDropdown from '../ServersDropdown'; +import { ServersDropdown } from '../ServersDropdown'; import DeleteServerModal from '../DeleteServerModal'; import DeleteServerButton from '../DeleteServerButton'; import { EditServer } from '../EditServer'; diff --git a/test/domains/helpers/EditDomainRedirectsModal.test.tsx b/test/domains/helpers/EditDomainRedirectsModal.test.tsx index 067f5f3b..3fc7205a 100644 --- a/test/domains/helpers/EditDomainRedirectsModal.test.tsx +++ b/test/domains/helpers/EditDomainRedirectsModal.test.tsx @@ -1,12 +1,10 @@ -import { shallow, ShallowWrapper } from 'enzyme'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { Mock } from 'ts-mockery'; -import { Button, ModalHeader } from 'reactstrap'; import { ShlinkDomain } from '../../../src/api/types'; import { EditDomainRedirectsModal } from '../../../src/domains/helpers/EditDomainRedirectsModal'; -import { InfoTooltip } from '../../../src/utils/InfoTooltip'; describe('', () => { - let wrapper: ShallowWrapper; const editDomainRedirects = jest.fn().mockResolvedValue(undefined); const toggle = jest.fn(); const domain = Mock.of({ @@ -15,81 +13,67 @@ describe('', () => { baseUrlRedirect: 'baz', }, }); - - beforeEach(() => { - wrapper = shallow( + const setUp = () => ({ + user: userEvent.setup(), + ...render( , - ); + ), }); afterEach(jest.clearAllMocks); - afterEach(() => wrapper?.unmount()); it('renders domain in header', () => { - const header = wrapper.find(ModalHeader); - - expect(header.html()).toContain('foo.com'); + setUp(); + expect(screen.getByRole('heading')).toHaveTextContent('Edit redirects for foo.com'); }); - it('expected amount of form groups and tooltips', () => { - const formGroups = wrapper.find('FormGroup'); - const tooltips = wrapper.find(InfoTooltip); + it('has different handlers to toggle the modal', async () => { + const { user } = setUp(); - expect(formGroups).toHaveLength(3); - expect(tooltips).toHaveLength(3); - }); - - it('has different handlers to toggle the modal', () => { expect(toggle).not.toHaveBeenCalled(); - - (wrapper.prop('toggle') as Function)(); - (wrapper.find(ModalHeader).prop('toggle') as Function)(); - wrapper.find(Button).first().simulate('click'); - - expect(toggle).toHaveBeenCalledTimes(3); + await user.click(screen.getByLabelText('Close')); + await user.click(screen.getByRole('button', { name: 'Cancel' })); + expect(toggle).toHaveBeenCalledTimes(2); }); - it('saves expected values when form is submitted', () => { - const formGroups = wrapper.find('FormGroup'); + it('saves expected values when form is submitted', async () => { + const { user } = setUp(); + // TODO Using fire event because userEvent.click on the Submit button does not submit the form + const submitForm = () => fireEvent.submit(screen.getByRole('form')); expect(editDomainRedirects).not.toHaveBeenCalled(); - - wrapper.find('form').simulate('submit', { preventDefault: jest.fn() }); - expect(editDomainRedirects).toHaveBeenCalledWith('foo.com', { + submitForm(); + await waitFor(() => expect(editDomainRedirects).toHaveBeenCalledWith('foo.com', { baseUrlRedirect: 'baz', regular404Redirect: null, invalidShortUrlRedirect: null, - }); + })); - formGroups.at(0).simulate('change', 'new_base_url'); - formGroups.at(2).simulate('change', 'new_invalid_short_url'); - - wrapper.find('form').simulate('submit', { preventDefault: jest.fn() }); - expect(editDomainRedirects).toHaveBeenCalledWith('foo.com', { + await user.clear(screen.getByDisplayValue('baz')); + await user.type(screen.getAllByPlaceholderText('No redirect')[0], 'new_base_url'); + await user.type(screen.getAllByPlaceholderText('No redirect')[2], 'new_invalid_short_url'); + submitForm(); + await waitFor(() => expect(editDomainRedirects).toHaveBeenCalledWith('foo.com', { baseUrlRedirect: 'new_base_url', regular404Redirect: null, invalidShortUrlRedirect: 'new_invalid_short_url', - }); + })); - formGroups.at(1).simulate('change', 'new_regular_404'); - formGroups.at(2).simulate('change', ''); - - wrapper.find('form').simulate('submit', { preventDefault: jest.fn() }); - expect(editDomainRedirects).toHaveBeenCalledWith('foo.com', { + await user.type(screen.getAllByPlaceholderText('No redirect')[1], 'new_regular_404'); + await user.clear(screen.getByDisplayValue('new_invalid_short_url')); + submitForm(); + await waitFor(() => expect(editDomainRedirects).toHaveBeenCalledWith('foo.com', { baseUrlRedirect: 'new_base_url', regular404Redirect: 'new_regular_404', invalidShortUrlRedirect: null, - }); + })); - formGroups.at(0).simulate('change', ''); - formGroups.at(1).simulate('change', ''); - formGroups.at(2).simulate('change', ''); - - wrapper.find('form').simulate('submit', { preventDefault: jest.fn() }); - expect(editDomainRedirects).toHaveBeenCalledWith('foo.com', { + await Promise.all(screen.getAllByPlaceholderText('No redirect').map((element) => user.clear(element))); + submitForm(); + await waitFor(() => expect(editDomainRedirects).toHaveBeenCalledWith('foo.com', { baseUrlRedirect: null, regular404Redirect: null, invalidShortUrlRedirect: null, - }); + })); }); }); diff --git a/test/servers/ServersDropdown.test.tsx b/test/servers/ServersDropdown.test.tsx index eab1eca2..19e8e616 100644 --- a/test/servers/ServersDropdown.test.tsx +++ b/test/servers/ServersDropdown.test.tsx @@ -1,44 +1,50 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { values } from 'ramda'; import { Mock } from 'ts-mockery'; -import { shallow, ShallowWrapper } from 'enzyme'; -import { DropdownItem, DropdownToggle } from 'reactstrap'; -import ServersDropdown from '../../src/servers/ServersDropdown'; -import { ServerWithId } from '../../src/servers/data'; +import { MemoryRouter } from 'react-router-dom'; +import { ServersDropdown } from '../../src/servers/ServersDropdown'; +import { ServersMap, ServerWithId } from '../../src/servers/data'; describe('', () => { - let wrapped: ShallowWrapper; - const servers = { + const fallbackServers: ServersMap = { '1a': Mock.of({ name: 'foo', id: '1a' }), '2b': Mock.of({ name: 'bar', id: '2b' }), '3c': Mock.of({ name: 'baz', id: '3c' }), }; - - beforeEach(() => { - wrapped = shallow(); - }); - afterEach(() => wrapped.unmount()); - - it('contains the list of servers, the divider, the create button and the export button', () => - expect(wrapped.find(DropdownItem)).toHaveLength(values(servers).length + 2)); - - it('contains a toggle with proper title', () => - expect(wrapped.find(DropdownToggle)).toHaveLength(1)); - - it('contains a button to export servers', () => { - const items = wrapped.find(DropdownItem); - - expect(items.filter('[divider]')).toHaveLength(1); - expect(items.filterWhere((item) => item.prop('to') === '/manage-servers')).toHaveLength(1); + const setUp = (servers: ServersMap = fallbackServers) => ({ + user: userEvent.setup(), + ...render(), }); - it('shows only create link when no servers exist yet', () => { - wrapped = shallow( - , - ); - const item = wrapped.find(DropdownItem); + it('contains the list of servers and the "mange servers" button', async () => { + const { user } = setUp(); - expect(item).toHaveLength(1); - expect(item.prop('to')).toEqual('/server/create'); - expect(item.find('span').text()).toContain('Add a server'); + await user.click(screen.getByText('Servers')); + const items = screen.getAllByRole('menuitem'); + expect(items).toHaveLength(values(fallbackServers).length + 1); + expect(items[0]).toHaveTextContent('foo'); + expect(items[1]).toHaveTextContent('bar'); + expect(items[2]).toHaveTextContent('baz'); + expect(items[3]).toHaveTextContent('Manage servers'); + }); + + it('contains a toggle with proper text', () => { + setUp(); + expect(screen.getByRole('link')).toHaveTextContent('Servers'); + }); + + it('contains a button to manage servers', async () => { + const { user } = setUp(); + + await user.click(screen.getByText('Servers')); + expect(screen.getByRole('menuitem', { name: 'Manage servers' })).toHaveAttribute('href', '/manage-servers'); + }); + + it('shows only create link when no servers exist yet', async () => { + const { user } = setUp({}); + + await user.click(screen.getByText('Servers')); + expect(screen.getByRole('menuitem')).toHaveTextContent('Add a server'); }); });