Migrated TagsList to react testing library

This commit is contained in:
Alejandro Celaya 2022-05-27 13:42:30 +02:00
parent 744cea1f11
commit 27a05e55c9
3 changed files with 33 additions and 80 deletions

View file

@ -30,7 +30,7 @@ export interface TagsListProps {
settings: Settings;
}
const TagsList = (TagsCards: FC<TagsListChildrenProps>, TagsTable: FC<TagsTableProps>) => boundToMercureHub((
export const TagsList = (TagsCards: FC<TagsListChildrenProps>, TagsTable: FC<TagsTableProps>) => boundToMercureHub((
{ filterTags, forceListTags, tagsList, selectedServer, settings }: TagsListProps,
) => {
const [mode, setMode] = useState<TagsMode>(settings.tags?.defaultMode ?? 'cards');
@ -104,5 +104,3 @@ const TagsList = (TagsCards: FC<TagsListChildrenProps>, TagsTable: FC<TagsTableP
</>
);
}, () => [Topics.visits]);
export default TagsList;

View file

@ -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';

View file

@ -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('<TagsList />', () => {
let wrapper: ShallowWrapper;
const filterTags = jest.fn();
const TagsCards = () => null;
const TagsTable = () => null;
const TagsListComp = createTagsList(TagsCards, TagsTable);
const createWrapper = (tagsList: Partial<TagsList>) => {
wrapper = shallow(
const TagsListComp = createTagsList(() => <>TagsCards</>, () => <>TagsTable</>);
const setUp = (tagsList: Partial<TagsList>) => ({
user: userEvent.setup(),
...render(
<TagsListComp
{...Mock.all<TagsListProps>()}
{...Mock.of<MercureBoundProps>({ mercureInfo: {} })}
@ -28,89 +21,51 @@ describe('<TagsList />', () => {
tagsList={Mock.of<TagsList>(tagsList)}
settings={Mock.all<Settings>()}
/>,
).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));
});
});