From 2f76c5381f226a1c7a07490af315ca48455b2737 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Fri, 24 Sep 2021 19:55:26 +0200 Subject: [PATCH] Added some tests for new tags components --- src/tags/TagsCards.tsx | 33 ++++++++++++++++++++ src/tags/TagsList.tsx | 43 ++++++++------------------ src/tags/data/TagsListChildrenProps.ts | 7 +++++ src/tags/services/provideServices.ts | 9 +++++- test/tags/TagsCards.test.tsx | 37 ++++++++++++++++++++++ test/tags/TagsList.test.tsx | 39 ++++++++++------------- 6 files changed, 115 insertions(+), 53 deletions(-) create mode 100644 src/tags/TagsCards.tsx create mode 100644 src/tags/data/TagsListChildrenProps.ts create mode 100644 test/tags/TagsCards.test.tsx diff --git a/src/tags/TagsCards.tsx b/src/tags/TagsCards.tsx new file mode 100644 index 00000000..3c1408cb --- /dev/null +++ b/src/tags/TagsCards.tsx @@ -0,0 +1,33 @@ +import { FC, useState } from 'react'; +import { splitEvery } from 'ramda'; +import { Row } from 'reactstrap'; +import { TagCardProps } from './TagCard'; +import { TagsListChildrenProps } from './data/TagsListChildrenProps'; + +const { ceil } = Math; +const TAGS_GROUPS_AMOUNT = 4; + +export const TagsCards = (TagCard: FC): FC => ({ tagsList, selectedServer }) => { + const [ displayedTag, setDisplayedTag ] = useState(); + const tagsCount = tagsList.filteredTags.length; + const tagsGroups = splitEvery(ceil(tagsCount / TAGS_GROUPS_AMOUNT), tagsList.filteredTags); + + return ( + + {tagsGroups.map((group, index) => ( +
+ {group.map((tag) => ( + setDisplayedTag(displayedTag !== tag ? tag : undefined)} + /> + ))} +
+ ))} +
+ ); +}; diff --git a/src/tags/TagsList.tsx b/src/tags/TagsList.tsx index 7b05d4bd..513c449b 100644 --- a/src/tags/TagsList.tsx +++ b/src/tags/TagsList.tsx @@ -1,5 +1,4 @@ import { FC, useEffect, useState } from 'react'; -import { splitEvery } from 'ramda'; import { Row } from 'reactstrap'; import Message from '../utils/Message'; import SearchField from '../utils/SearchField'; @@ -9,10 +8,8 @@ import { Result } from '../utils/Result'; import { ShlinkApiError } from '../api/ShlinkApiError'; import { Topics } from '../mercure/helpers/Topics'; import { TagsList as TagsListState } from './reducers/tagsList'; -import { TagCardProps } from './TagCard'; - -const { ceil } = Math; -const TAGS_GROUPS_AMOUNT = 4; +import { TagsListChildrenProps } from './data/TagsListChildrenProps'; +import { TagsMode, TagsModeDropdown } from './TagsModeDropdown'; export interface TagsListProps { filterTags: (searchTerm: string) => void; @@ -21,10 +18,10 @@ export interface TagsListProps { selectedServer: SelectedServer; } -const TagsList = (TagCard: FC) => boundToMercureHub(( +const TagsList = (TagsCards: FC, TagsTable: FC) => boundToMercureHub(( { filterTags, forceListTags, tagsList, selectedServer }: TagsListProps, ) => { - const [ displayedTag, setDisplayedTag ] = useState(); + const [ mode, setMode ] = useState('cards'); useEffect(() => { forceListTags(); @@ -43,37 +40,23 @@ const TagsList = (TagCard: FC) => boundToMercureHub(( ); } - const tagsCount = tagsList.filteredTags.length; - - if (tagsCount < 1) { + if (tagsList.filteredTags.length < 1) { return No tags found; } - const tagsGroups = splitEvery(ceil(tagsCount / TAGS_GROUPS_AMOUNT), tagsList.filteredTags); - - return ( - - {tagsGroups.map((group, index) => ( -
- {group.map((tag) => ( - setDisplayedTag(displayedTag !== tag ? tag : undefined)} - /> - ))} -
- ))} -
- ); + return mode === 'cards' + ? + : ; }; return ( <> + +
+ +
+
{renderContent()} ); diff --git a/src/tags/data/TagsListChildrenProps.ts b/src/tags/data/TagsListChildrenProps.ts new file mode 100644 index 00000000..5777c290 --- /dev/null +++ b/src/tags/data/TagsListChildrenProps.ts @@ -0,0 +1,7 @@ +import { TagsList as TagsListState } from '../reducers/tagsList'; +import { SelectedServer } from '../../servers/data'; + +export interface TagsListChildrenProps { + tagsList: TagsListState; + selectedServer: SelectedServer; +} diff --git a/src/tags/services/provideServices.ts b/src/tags/services/provideServices.ts index ba5951c1..f28d048b 100644 --- a/src/tags/services/provideServices.ts +++ b/src/tags/services/provideServices.ts @@ -8,6 +8,9 @@ import { filterTags, listTags } from '../reducers/tagsList'; import { deleteTag, tagDeleted } from '../reducers/tagDelete'; import { editTag, tagEdited } from '../reducers/tagEdit'; import { ConnectDecorator } from '../../container/types'; +import { TagsCards } from '../TagsCards'; +import { TagsTable } from '../TagsTable'; +import { TagsTableRow } from '../TagsTableRow'; const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { // Components @@ -29,7 +32,11 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { bottle.serviceFactory('EditTagModal', EditTagModal, 'ColorGenerator'); bottle.decorator('EditTagModal', connect([ 'tagEdit' ], [ 'editTag', 'tagEdited' ])); - bottle.serviceFactory('TagsList', TagsList, 'TagCard'); + bottle.serviceFactory('TagsCards', TagsCards, 'TagCard'); + bottle.serviceFactory('TagsTableRow', TagsTableRow, 'DeleteTagConfirmModal', 'EditTagModal'); + bottle.serviceFactory('TagsTable', TagsTable, 'ColorGenerator', 'TagsTableRow'); + + bottle.serviceFactory('TagsList', TagsList, 'TagsCards', 'TagsTable'); bottle.decorator('TagsList', connect( [ 'tagsList', 'selectedServer', 'mercureInfo' ], [ 'forceListTags', 'filterTags', 'createNewVisits', 'loadMercureInfo' ], diff --git a/test/tags/TagsCards.test.tsx b/test/tags/TagsCards.test.tsx new file mode 100644 index 00000000..0ef3fed9 --- /dev/null +++ b/test/tags/TagsCards.test.tsx @@ -0,0 +1,37 @@ +import { shallow, ShallowWrapper } from 'enzyme'; +import { Mock } from 'ts-mockery'; +import { TagsCards as createTagsCards } from '../../src/tags/TagsCards'; +import { TagsList } from '../../src/tags/reducers/tagsList'; +import { SelectedServer } from '../../src/servers/data'; +import { rangeOf } from '../../src/utils/utils'; + +describe('', () => { + const amountOfTags = 10; + const tagsList = Mock.of({ filteredTags: rangeOf(amountOfTags, (i) => `tag_${i}`), stats: {} }); + const TagCard = () => null; + const TagsCards = createTagsCards(TagCard); + let wrapper: ShallowWrapper; + + beforeEach(() => { + wrapper = shallow(()} />); + }); + + afterEach(() => wrapper?.unmount()); + + it('renders the proper amount of groups and cards based on the amount of tags', () => { + const amountOfGroups = 4; + const cards = wrapper.find(TagCard); + const groups = wrapper.find('.col-md-6'); + + expect(cards).toHaveLength(amountOfTags); + expect(groups).toHaveLength(amountOfGroups); + }); + + it('displays card on toggle', () => { + const card = () => wrapper.find(TagCard).at(5); + + expect(card().prop('displayed')).toEqual(false); + (card().prop('toggle') as Function)(); // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion + expect(card().prop('displayed')).toEqual(true); + }); +}); diff --git a/test/tags/TagsList.test.tsx b/test/tags/TagsList.test.tsx index 072f3b6f..5f1efc23 100644 --- a/test/tags/TagsList.test.tsx +++ b/test/tags/TagsList.test.tsx @@ -3,19 +3,19 @@ import { identity } from 'ramda'; import { Mock } from 'ts-mockery'; import createTagsList, { TagsListProps } from '../../src/tags/TagsList'; import Message from '../../src/utils/Message'; -import SearchField from '../../src/utils/SearchField'; -import { rangeOf } from '../../src/utils/utils'; 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'; describe('', () => { let wrapper: ShallowWrapper; const filterTags = jest.fn(); - const TagCard = () => null; + const TagsCards = () => null; + const TagsTable = () => null; + const TagsListComp = createTagsList(TagsCards, TagsTable); const createWrapper = (tagsList: Partial) => { - const TagsListComp = createTagsList(TagCard); - wrapper = shallow( ()} @@ -56,28 +56,23 @@ describe('', () => { expect(msg.html()).toContain('No tags found'); }); - it('renders the proper amount of groups and cards based on the amount of tags', () => { - const amountOfTags = 10; - const amountOfGroups = 4; - const wrapper = createWrapper({ filteredTags: rangeOf(amountOfTags, (i) => `tag_${i}`), stats: {} }); - const cards = wrapper.find(TagCard); - const groups = wrapper.find('.col-md-6'); + it('renders proper component based on the display mode', () => { + const wrapper = createWrapper({ filteredTags: [ 'foo', 'bar' ], stats: {} }); - expect(cards).toHaveLength(amountOfTags); - expect(groups).toHaveLength(amountOfGroups); + expect(wrapper.find(TagsCards)).toHaveLength(1); + expect(wrapper.find(TagsTable)).toHaveLength(0); + + wrapper.find(TagsModeDropdown).simulate('change'); + + expect(wrapper.find(TagsCards)).toHaveLength(0); + expect(wrapper.find(TagsTable)).toHaveLength(1); }); - it('triggers tags filtering when search field changes', (done) => { + it('triggers tags filtering when search field changes', () => { const wrapper = createWrapper({ filteredTags: [] }); - const searchField = wrapper.find(SearchField); - expect(searchField).toHaveLength(1); expect(filterTags).not.toHaveBeenCalled(); - searchField.simulate('change'); - - setImmediate(() => { - expect(filterTags).toHaveBeenCalledTimes(1); - done(); - }); + wrapper.find(SearchField).simulate('change'); + expect(filterTags).toHaveBeenCalledTimes(1); }); });