Merge branch 'add-tests' into 'develop'
Add tests for Groups discover components See merge request soapbox-pub/soapbox!2483
This commit is contained in:
commit
799b845467
16 changed files with 304 additions and 8 deletions
77
app/soapbox/features/groups/__tests__/discover.test.tsx
Normal file
77
app/soapbox/features/groups/__tests__/discover.test.tsx
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { render, screen, waitFor } from 'soapbox/jest/test-helpers';
|
||||||
|
import { normalizeAccount, normalizeInstance } from 'soapbox/normalizers';
|
||||||
|
|
||||||
|
import Discover from '../discover';
|
||||||
|
|
||||||
|
jest.mock('../../../hooks/useDimensions', () => ({
|
||||||
|
useDimensions: () => [{ scrollWidth: 190 }, null, { width: 300 }],
|
||||||
|
}));
|
||||||
|
|
||||||
|
(window as any).ResizeObserver = class ResizeObserver {
|
||||||
|
|
||||||
|
observe() { }
|
||||||
|
disconnect() { }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const userId = '1';
|
||||||
|
const store: any = {
|
||||||
|
me: userId,
|
||||||
|
accounts: ImmutableMap({
|
||||||
|
[userId]: normalizeAccount({
|
||||||
|
id: userId,
|
||||||
|
acct: 'justin-username',
|
||||||
|
display_name: 'Justin L',
|
||||||
|
avatar: 'test.jpg',
|
||||||
|
chats_onboarded: false,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
instance: normalizeInstance({
|
||||||
|
version: '3.4.1 (compatible; TruthSocial 1.0.0)',
|
||||||
|
software: 'TRUTHSOCIAL',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderApp = () => (
|
||||||
|
render(
|
||||||
|
<Discover />,
|
||||||
|
undefined,
|
||||||
|
store,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('<Discover />', () => {
|
||||||
|
describe('before the user starts searching', () => {
|
||||||
|
it('it should render popular groups', async () => {
|
||||||
|
renderApp();
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTestId('popular-groups')).toBeInTheDocument();
|
||||||
|
expect(screen.getByTestId('suggested-groups')).toBeInTheDocument();
|
||||||
|
expect(screen.getByTestId('popular-tags')).toBeInTheDocument();
|
||||||
|
expect(screen.queryAllByTestId('recent-searches')).toHaveLength(0);
|
||||||
|
expect(screen.queryAllByTestId('group-search-icon')).toHaveLength(0);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the user focuses on the input', () => {
|
||||||
|
it('should render the search experience', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderApp();
|
||||||
|
|
||||||
|
await user.click(screen.getByTestId('search'));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTestId('group-search-icon')).toBeInTheDocument();
|
||||||
|
expect(screen.getByTestId('recent-searches')).toBeInTheDocument();
|
||||||
|
expect(screen.queryAllByTestId('popular-groups')).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { buildGroup } from 'soapbox/jest/factory';
|
||||||
|
import { render, screen } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
|
import GroupGridItem from '../group-grid-item';
|
||||||
|
|
||||||
|
describe('<GroupGridItem', () => {
|
||||||
|
it('should render correctly', () => {
|
||||||
|
const group = buildGroup({
|
||||||
|
display_name: 'group name here',
|
||||||
|
locked: false,
|
||||||
|
members_count: 6,
|
||||||
|
});
|
||||||
|
render(<GroupGridItem group={group} />);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('group-grid-item')).toHaveTextContent(group.display_name);
|
||||||
|
expect(screen.getByTestId('group-grid-item')).toHaveTextContent('Public');
|
||||||
|
expect(screen.getByTestId('group-grid-item')).toHaveTextContent('6 members');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { buildGroup } from 'soapbox/jest/factory';
|
||||||
|
import { render, screen } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
|
import GroupListItem from '../group-list-item';
|
||||||
|
|
||||||
|
describe('<GroupListItem', () => {
|
||||||
|
it('should render correctly', () => {
|
||||||
|
const group = buildGroup({
|
||||||
|
display_name: 'group name here',
|
||||||
|
locked: false,
|
||||||
|
members_count: 6,
|
||||||
|
});
|
||||||
|
render(<GroupListItem group={group} />);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('group-list-item')).toHaveTextContent(group.display_name);
|
||||||
|
expect(screen.getByTestId('group-list-item')).toHaveTextContent('Public');
|
||||||
|
expect(screen.getByTestId('group-list-item')).toHaveTextContent('6 members');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,38 @@
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { render, screen, within } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
|
import LayoutButtons, { GroupLayout } from '../layout-buttons';
|
||||||
|
|
||||||
|
describe('<LayoutButtons', () => {
|
||||||
|
describe('when LIST view', () => {
|
||||||
|
it('should render correctly', async () => {
|
||||||
|
const onSelectFn = jest.fn();
|
||||||
|
const user = userEvent.setup();
|
||||||
|
|
||||||
|
render(<LayoutButtons layout={GroupLayout.LIST} onSelect={onSelectFn} />);
|
||||||
|
|
||||||
|
expect(within(screen.getByTestId('layout-list-action')).getByTestId('svg-icon-loader')).toHaveClass('text-primary-600');
|
||||||
|
expect(within(screen.getByTestId('layout-grid-action')).getByTestId('svg-icon-loader')).not.toHaveClass('text-primary-600');
|
||||||
|
|
||||||
|
await user.click(screen.getByTestId('layout-grid-action'));
|
||||||
|
expect(onSelectFn).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when GRID view', () => {
|
||||||
|
it('should render correctly', async () => {
|
||||||
|
const onSelectFn = jest.fn();
|
||||||
|
const user = userEvent.setup();
|
||||||
|
|
||||||
|
render(<LayoutButtons layout={GroupLayout.GRID} onSelect={onSelectFn} />);
|
||||||
|
|
||||||
|
expect(within(screen.getByTestId('layout-list-action')).getByTestId('svg-icon-loader')).not.toHaveClass('text-primary-600');
|
||||||
|
expect(within(screen.getByTestId('layout-grid-action')).getByTestId('svg-icon-loader')).toHaveClass('text-primary-600');
|
||||||
|
|
||||||
|
await user.click(screen.getByTestId('layout-grid-action'));
|
||||||
|
expect(onSelectFn).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,16 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { buildGroupTag } from 'soapbox/jest/factory';
|
||||||
|
import { render, screen } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
|
import TagListItem from '../tag-list-item';
|
||||||
|
|
||||||
|
describe('<TagListItem', () => {
|
||||||
|
it('should render correctly', () => {
|
||||||
|
const tag = buildGroupTag({ name: 'tag 1', groups: 5 });
|
||||||
|
render(<TagListItem tag={tag} />);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('tag-list-item')).toHaveTextContent(tag.name);
|
||||||
|
expect(screen.getByTestId('tag-list-item')).toHaveTextContent('Number of groups: 5');
|
||||||
|
});
|
||||||
|
});
|
|
@ -25,6 +25,7 @@ const GroupGridItem = forwardRef((props: IGroup, ref: React.ForwardedRef<HTMLDiv
|
||||||
style={{
|
style={{
|
||||||
width,
|
width,
|
||||||
}}
|
}}
|
||||||
|
data-testid='group-grid-item'
|
||||||
>
|
>
|
||||||
<Link to={`/group/${group.slug}`}>
|
<Link to={`/group/${group.slug}`}>
|
||||||
<Stack
|
<Stack
|
||||||
|
|
|
@ -20,6 +20,7 @@ const GroupListItem = (props: IGroup) => {
|
||||||
<HStack
|
<HStack
|
||||||
alignItems='center'
|
alignItems='center'
|
||||||
justifyContent='between'
|
justifyContent='between'
|
||||||
|
data-testid='group-list-item'
|
||||||
>
|
>
|
||||||
<Link key={group.id} to={`/group/${group.slug}`}>
|
<Link key={group.id} to={`/group/${group.slug}`}>
|
||||||
<HStack alignItems='center' space={2}>
|
<HStack alignItems='center' space={2}>
|
||||||
|
|
|
@ -15,7 +15,10 @@ interface ILayoutButtons {
|
||||||
|
|
||||||
const LayoutButtons = ({ layout, onSelect }: ILayoutButtons) => (
|
const LayoutButtons = ({ layout, onSelect }: ILayoutButtons) => (
|
||||||
<HStack alignItems='center' space={1}>
|
<HStack alignItems='center' space={1}>
|
||||||
<button onClick={() => onSelect(GroupLayout.LIST)}>
|
<button
|
||||||
|
data-testid='layout-list-action'
|
||||||
|
onClick={() => onSelect(GroupLayout.LIST)}
|
||||||
|
>
|
||||||
<Icon
|
<Icon
|
||||||
src={require('@tabler/icons/layout-list.svg')}
|
src={require('@tabler/icons/layout-list.svg')}
|
||||||
className={
|
className={
|
||||||
|
@ -26,7 +29,10 @@ const LayoutButtons = ({ layout, onSelect }: ILayoutButtons) => (
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button onClick={() => onSelect(GroupLayout.GRID)}>
|
<button
|
||||||
|
data-testid='layout-grid-action'
|
||||||
|
onClick={() => onSelect(GroupLayout.GRID)}
|
||||||
|
>
|
||||||
<Icon
|
<Icon
|
||||||
src={require('@tabler/icons/layout-grid.svg')}
|
src={require('@tabler/icons/layout-grid.svg')}
|
||||||
className={
|
className={
|
||||||
|
|
|
@ -15,7 +15,7 @@ const PopularGroups = () => {
|
||||||
const [groupCover, setGroupCover] = useState<HTMLDivElement | null>(null);
|
const [groupCover, setGroupCover] = useState<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack space={4}>
|
<Stack space={4} data-testid='popular-groups'>
|
||||||
<HStack alignItems='center' justifyContent='between'>
|
<HStack alignItems='center' justifyContent='between'>
|
||||||
<Text size='xl' weight='bold'>
|
<Text size='xl' weight='bold'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
|
|
@ -12,7 +12,7 @@ const PopularTags = () => {
|
||||||
const isEmpty = (isFetched && tags.length === 0) || isError;
|
const isEmpty = (isFetched && tags.length === 0) || isError;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack space={4}>
|
<Stack space={4} data-testid='popular-tags'>
|
||||||
<HStack alignItems='center' justifyContent='between'>
|
<HStack alignItems='center' justifyContent='between'>
|
||||||
<Text size='xl' weight='bold'>
|
<Text size='xl' weight='bold'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { render, screen } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
|
import Blankslate from '../blankslate';
|
||||||
|
|
||||||
|
|
||||||
|
describe('<Blankslate />', () => {
|
||||||
|
describe('with string props', () => {
|
||||||
|
it('should render correctly', () => {
|
||||||
|
render(<Blankslate title='Title' subtitle='Subtitle' />);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('no-results')).toHaveTextContent('Title');
|
||||||
|
expect(screen.getByTestId('no-results')).toHaveTextContent('Subtitle');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with node props', () => {
|
||||||
|
it('should render correctly', () => {
|
||||||
|
render(
|
||||||
|
<Blankslate
|
||||||
|
title={<span>Title</span>}
|
||||||
|
subtitle={<span>Subtitle</span>}
|
||||||
|
/>);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('no-results')).toHaveTextContent('Title');
|
||||||
|
expect(screen.getByTestId('no-results')).toHaveTextContent('Subtitle');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,67 @@
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
import React from 'react';
|
||||||
|
import { VirtuosoGridMockContext, VirtuosoMockContext } from 'react-virtuoso';
|
||||||
|
|
||||||
|
import { buildGroup } from 'soapbox/jest/factory';
|
||||||
|
import { render, screen, waitFor } from 'soapbox/jest/test-helpers';
|
||||||
|
import { normalizeAccount } from 'soapbox/normalizers';
|
||||||
|
|
||||||
|
import Results from '../results';
|
||||||
|
|
||||||
|
const userId = '1';
|
||||||
|
const store = {
|
||||||
|
me: userId,
|
||||||
|
accounts: ImmutableMap({
|
||||||
|
[userId]: normalizeAccount({
|
||||||
|
id: userId,
|
||||||
|
acct: 'justin-username',
|
||||||
|
display_name: 'Justin L',
|
||||||
|
avatar: 'test.jpg',
|
||||||
|
chats_onboarded: false,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderApp = (children: React.ReactNode) => (
|
||||||
|
render(
|
||||||
|
<VirtuosoMockContext.Provider value={{ viewportHeight: 300, itemHeight: 100 }}>
|
||||||
|
<VirtuosoGridMockContext.Provider value={{ viewportHeight: 300, viewportWidth: 300, itemHeight: 100, itemWidth: 100 }}>
|
||||||
|
{children}
|
||||||
|
</VirtuosoGridMockContext.Provider>
|
||||||
|
</VirtuosoMockContext.Provider>,
|
||||||
|
undefined,
|
||||||
|
store,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const groupSearchResult = {
|
||||||
|
groups: [buildGroup()],
|
||||||
|
hasNextPage: false,
|
||||||
|
isFetching: false,
|
||||||
|
fetchNextPage: jest.fn(),
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
describe('<Results />', () => {
|
||||||
|
describe('with a list layout', () => {
|
||||||
|
it('should render the GroupListItem components', async () => {
|
||||||
|
renderApp(<Results groupSearchResult={groupSearchResult} />);
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTestId('group-list-item')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a grid layout', () => {
|
||||||
|
it('should render the GroupGridItem components', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderApp(<Results groupSearchResult={groupSearchResult} />);
|
||||||
|
|
||||||
|
await user.click(screen.getByTestId('layout-grid-action'));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTestId('group-grid-item')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -15,7 +15,7 @@ const SuggestedGroups = () => {
|
||||||
const [groupCover, setGroupCover] = useState<HTMLDivElement | null>(null);
|
const [groupCover, setGroupCover] = useState<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack space={4}>
|
<Stack space={4} data-testid='suggested-groups'>
|
||||||
<HStack alignItems='center' justifyContent='between'>
|
<HStack alignItems='center' justifyContent='between'>
|
||||||
<Text size='xl' weight='bold'>
|
<Text size='xl' weight='bold'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
|
|
@ -14,7 +14,11 @@ const TagListItem = (props: ITagListItem) => {
|
||||||
const { tag } = props;
|
const { tag } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link to={`/groups/discover/tags/${tag.id}`} className='group'>
|
<Link
|
||||||
|
to={`/groups/discover/tags/${tag.id}`}
|
||||||
|
className='group'
|
||||||
|
data-testid='tag-list-item'
|
||||||
|
>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Text
|
<Text
|
||||||
weight='bold'
|
weight='bold'
|
||||||
|
|
|
@ -39,6 +39,7 @@ const Discover: React.FC = () => {
|
||||||
src={require('@tabler/icons/arrow-left.svg')}
|
src={require('@tabler/icons/arrow-left.svg')}
|
||||||
iconClassName='mr-2 h-5 w-5 fill-current text-gray-600'
|
iconClassName='mr-2 h-5 w-5 fill-current text-gray-600'
|
||||||
onClick={cancelSearch}
|
onClick={cancelSearch}
|
||||||
|
data-testid='group-search-icon'
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import { groupSchema, Group, groupRelationshipSchema, GroupRelationship } from 'soapbox/schemas';
|
import {
|
||||||
|
groupSchema,
|
||||||
|
groupRelationshipSchema,
|
||||||
|
groupTagSchema,
|
||||||
|
type Group,
|
||||||
|
type GroupRelationship,
|
||||||
|
type GroupTag,
|
||||||
|
} from 'soapbox/schemas';
|
||||||
|
|
||||||
// TODO: there's probably a better way to create these factory functions.
|
// TODO: there's probably a better way to create these factory functions.
|
||||||
// This looks promising but didn't work on my first attempt: https://github.com/anatine/zod-plugins/tree/main/packages/zod-mock
|
// This looks promising but didn't work on my first attempt: https://github.com/anatine/zod-plugins/tree/main/packages/zod-mock
|
||||||
|
@ -17,4 +24,10 @@ function buildGroupRelationship(props: Record<string, any> = {}): GroupRelations
|
||||||
}, props));
|
}, props));
|
||||||
}
|
}
|
||||||
|
|
||||||
export { buildGroup, buildGroupRelationship };
|
function buildGroupTag(props: Record<string, any> = {}): GroupTag {
|
||||||
|
return groupTagSchema.parse(Object.assign({
|
||||||
|
id: uuidv4(),
|
||||||
|
}, props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export { buildGroup, buildGroupRelationship, buildGroupTag };
|
Loading…
Reference in a new issue