From 27a05e55c9ef2b08b870a50b34774f0f9d1126a7 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Fri, 27 May 2022 13:42:30 +0200 Subject: [PATCH] Migrated TagsList to react testing library --- src/tags/TagsList.tsx | 4 +- src/tags/services/provideServices.ts | 2 +- test/tags/TagsList.test.tsx | 107 ++++++++------------------- 3 files changed, 33 insertions(+), 80 deletions(-) diff --git a/src/tags/TagsList.tsx b/src/tags/TagsList.tsx index ca8c3ca7..fe64a26a 100644 --- a/src/tags/TagsList.tsx +++ b/src/tags/TagsList.tsx @@ -30,7 +30,7 @@ export interface TagsListProps { settings: Settings; } -const TagsList = (TagsCards: FC, TagsTable: FC) => boundToMercureHub(( +export const TagsList = (TagsCards: FC, TagsTable: FC) => boundToMercureHub(( { filterTags, forceListTags, tagsList, selectedServer, settings }: TagsListProps, ) => { const [mode, setMode] = useState(settings.tags?.defaultMode ?? 'cards'); @@ -104,5 +104,3 @@ const TagsList = (TagsCards: FC, TagsTable: FC ); }, () => [Topics.visits]); - -export default TagsList; diff --git a/src/tags/services/provideServices.ts b/src/tags/services/provideServices.ts index 5a1a4221..aca9130c 100644 --- a/src/tags/services/provideServices.ts +++ b/src/tags/services/provideServices.ts @@ -3,7 +3,7 @@ import TagsSelector from '../helpers/TagsSelector'; import TagCard from '../TagCard'; import DeleteTagConfirmModal from '../helpers/DeleteTagConfirmModal'; import EditTagModal from '../helpers/EditTagModal'; -import TagsList from '../TagsList'; +import { TagsList } from '../TagsList'; import { filterTags, listTags } from '../reducers/tagsList'; import { deleteTag, tagDeleted } from '../reducers/tagDelete'; import { editTag, tagEdited } from '../reducers/tagEdit'; diff --git a/test/tags/TagsList.test.tsx b/test/tags/TagsList.test.tsx index d642a060..f1639203 100644 --- a/test/tags/TagsList.test.tsx +++ b/test/tags/TagsList.test.tsx @@ -1,25 +1,18 @@ -import { shallow, ShallowWrapper } from 'enzyme'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { identity } from 'ramda'; import { Mock } from 'ts-mockery'; -import createTagsList, { TagsListProps } from '../../src/tags/TagsList'; -import Message from '../../src/utils/Message'; +import { TagsList as createTagsList, TagsListProps } from '../../src/tags/TagsList'; import { TagsList } from '../../src/tags/reducers/tagsList'; import { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; -import { Result } from '../../src/utils/Result'; -import { TagsModeDropdown } from '../../src/tags/TagsModeDropdown'; -import { SearchField } from '../../src/utils/SearchField'; import { Settings } from '../../src/settings/reducers/settings'; -import { TagsOrderableFields } from '../../src/tags/data/TagsListChildrenProps'; -import { OrderingDropdown } from '../../src/utils/OrderingDropdown'; describe('', () => { - let wrapper: ShallowWrapper; const filterTags = jest.fn(); - const TagsCards = () => null; - const TagsTable = () => null; - const TagsListComp = createTagsList(TagsCards, TagsTable); - const createWrapper = (tagsList: Partial) => { - wrapper = shallow( + const TagsListComp = createTagsList(() => <>TagsCards, () => <>TagsTable); + const setUp = (tagsList: Partial) => ({ + user: userEvent.setup(), + ...render( ()} {...Mock.of({ mercureInfo: {} })} @@ -28,89 +21,51 @@ describe('', () => { tagsList={Mock.of(tagsList)} settings={Mock.all()} />, - ).dive(); // Dive is needed as this component is wrapped in a HOC + ), + }); - return wrapper; - }; - - afterEach(() => wrapper?.unmount()); afterEach(jest.clearAllMocks); it('shows a loading message when tags are being loaded', () => { - const wrapper = createWrapper({ loading: true }); - const loadingMsg = wrapper.find(Message); - const searchField = wrapper.find(SearchField); + setUp({ loading: true }); - expect(loadingMsg).toHaveLength(1); - expect(loadingMsg.html()).toContain('Loading...'); - expect(searchField).toHaveLength(0); + expect(screen.getByText('Loading...')).toBeInTheDocument(); + expect(screen.queryByText('Error loading tags :(')).not.toBeInTheDocument(); }); it('shows an error when tags failed to be loaded', () => { - const wrapper = createWrapper({ error: true }); - const errorMsg = wrapper.find(Result).filterWhere((result) => result.prop('type') === 'error'); - const searchField = wrapper.find(SearchField); + setUp({ error: true }); - expect(errorMsg).toHaveLength(1); - expect(errorMsg.html()).toContain('Error loading tags :('); - expect(searchField).toHaveLength(0); + expect(screen.getByText('Error loading tags :(')).toBeInTheDocument(); + expect(screen.queryByText('Loading')).not.toBeInTheDocument(); }); it('shows a message when the list of tags is empty', () => { - const wrapper = createWrapper({ filteredTags: [] }); - const msg = wrapper.find(Message); + setUp({ filteredTags: [] }); - expect(msg).toHaveLength(1); - expect(msg.html()).toContain('No tags found'); + expect(screen.getByText('No tags found')).toBeInTheDocument(); + expect(screen.queryByText('Error loading tags :(')).not.toBeInTheDocument(); + expect(screen.queryByText('Loading')).not.toBeInTheDocument(); }); - it('renders proper component based on the display mode', () => { - const wrapper = createWrapper({ filteredTags: ['foo', 'bar'], stats: {} }); + it('renders proper component based on the display mode', async () => { + const { user } = setUp({ filteredTags: ['foo', 'bar'], stats: {} }); - expect(wrapper.find(TagsCards)).toHaveLength(1); - expect(wrapper.find(TagsTable)).toHaveLength(0); + expect(screen.getByText('TagsCards')).toBeInTheDocument(); + expect(screen.queryByText('TagsTable')).not.toBeInTheDocument(); - wrapper.find(TagsModeDropdown).simulate('change'); + await user.click(screen.getByRole('button', { name: /^Display mode/ })); + await user.click(screen.getByRole('menuitem', { name: /List/ })); - expect(wrapper.find(TagsCards)).toHaveLength(0); - expect(wrapper.find(TagsTable)).toHaveLength(1); + expect(screen.queryByText('TagsCards')).not.toBeInTheDocument(); + expect(screen.getByText('TagsTable')).toBeInTheDocument(); }); - it('triggers tags filtering when search field changes', () => { - const wrapper = createWrapper({ filteredTags: [] }); - const searchField = wrapper.find(SearchField); + it('triggers tags filtering when search field changes', async () => { + const { user } = setUp({ filteredTags: [] }); - expect(searchField).toHaveLength(1); expect(filterTags).not.toHaveBeenCalled(); - searchField.simulate('change'); - expect(filterTags).toHaveBeenCalledTimes(1); - }); - - it('triggers ordering when sorting dropdown changes', () => { - const wrapper = createWrapper({ filteredTags: [] }); - - expect(wrapper.find(OrderingDropdown).prop('order')).toEqual({}); - wrapper.find(OrderingDropdown).simulate('change', 'tag', 'DESC'); - expect(wrapper.find(OrderingDropdown).prop('order')).toEqual({ field: 'tag', dir: 'DESC' }); - wrapper.find(OrderingDropdown).simulate('change', 'visits', 'ASC'); - expect(wrapper.find(OrderingDropdown).prop('order')).toEqual({ field: 'visits', dir: 'ASC' }); - }); - - it('can update current order via orderByColumn from table component', () => { - const wrapper = createWrapper({ filteredTags: ['foo', 'bar'], stats: {} }); - const callOrderBy = (field: TagsOrderableFields) => { - ((wrapper.find(TagsTable).prop('orderByColumn') as Function)(field) as Function)(); - }; - - wrapper.find(TagsModeDropdown).simulate('change'); // Make sure table is rendered - - callOrderBy('visits'); - expect(wrapper.find(TagsTable).prop('currentOrder')).toEqual({ field: 'visits', dir: 'ASC' }); - callOrderBy('visits'); - expect(wrapper.find(TagsTable).prop('currentOrder')).toEqual({ field: 'visits', dir: 'DESC' }); - callOrderBy('tag'); - expect(wrapper.find(TagsTable).prop('currentOrder')).toEqual({ field: 'tag', dir: 'ASC' }); - callOrderBy('shortUrls'); - expect(wrapper.find(TagsTable).prop('currentOrder')).toEqual({ field: 'shortUrls', dir: 'ASC' }); + await user.type(screen.getByPlaceholderText('Search...'), 'Hello'); + await waitFor(() => expect(filterTags).toHaveBeenCalledTimes(1)); }); });