Add tests for ChatPane component

This commit is contained in:
Justin 2022-10-03 11:03:43 -04:00
parent e4ed68e070
commit 89af43df91
8 changed files with 200 additions and 30 deletions

View File

@ -21,6 +21,11 @@ export const getLinks = (response: AxiosResponse): LinkHeader => {
return new LinkHeader(response.headers?.link);
};
export const getNextLink = (response: AxiosResponse) => {
const nextLink = new LinkHeader(response.headers?.link);
return nextLink.refs.find((ref) => ref.uri)?.uri;
};
export const baseClient = (...params: any[]) => {
const axios = api.baseClient(...params);
setupMock(axios);

View File

@ -82,7 +82,7 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, chatSilence, onC
key={chat.id}
onClick={() => onClick(chat)}
className='group px-2 py-3 w-full flex flex-col rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 focus:shadow-inset-ring'
data-testid='chat'
data-testid='chat-list-item'
>
<HStack alignItems='center' justifyContent='between' space={2} className='w-full'>
<HStack alignItems='center' space={2} className='overflow-hidden'>

View File

@ -4,7 +4,7 @@ import { Virtuoso } from 'react-virtuoso';
import { fetchChats } from 'soapbox/actions/chats';
import PullToRefresh from 'soapbox/components/pull-to-refresh';
import { Stack } from 'soapbox/components/ui';
import { Spinner, Stack } from 'soapbox/components/ui';
import PlaceholderChat from 'soapbox/features/placeholder/components/placeholder-chat';
import { useAppDispatch } from 'soapbox/hooks';
import { useChats, useChatSilences } from 'soapbox/queries/chats';
@ -29,15 +29,13 @@ const ChatList: React.FC<IChatList> = ({ onClickChat, useWindowScroll = false, s
const [isNearBottom, setNearBottom] = useState<boolean>(false);
const [isNearTop, setNearTop] = useState<boolean>(true);
const isEmpty = (!chats || chats.length === 0);
const handleLoadMore = () => {
if (hasNextPage && !isFetching) {
fetchNextPage();
}
};
const handleRefresh = () => dispatch(fetchChats()) as any;
const handleRefresh = () => dispatch(fetchChats());
const renderEmpty = () => (
<Stack space={2}>
@ -50,29 +48,27 @@ const ChatList: React.FC<IChatList> = ({ onClickChat, useWindowScroll = false, s
return (
<div className='relative h-full'>
<PullToRefresh onRefresh={handleRefresh}>
{isEmpty ? renderEmpty() : (
<Virtuoso
ref={chatListRef}
atTopStateChange={(atTop) => setNearTop(atTop)}
atBottomStateChange={(atBottom) => setNearBottom(atBottom)}
useWindowScroll={useWindowScroll}
data={chats}
endReached={handleLoadMore}
itemContent={(_index, chat) => {
const chatSilence = chatSilences?.find((chatSilence) => String(chatSilence.target_account_id) === chat.account.id);
return (
<div className='px-2'>
<ChatListItem chat={chat} onClick={onClickChat} chatSilence={chatSilence} />
</div>
);
}}
components={{
ScrollSeekPlaceholder: () => <PlaceholderChat />,
// Footer: () => hasNextPage ? <Spinner withText={false} /> : null,
EmptyPlaceholder: renderEmpty,
}}
/>
)}
<Virtuoso
ref={chatListRef}
atTopStateChange={(atTop) => setNearTop(atTop)}
atBottomStateChange={(atBottom) => setNearBottom(atBottom)}
useWindowScroll={useWindowScroll}
data={chats}
endReached={handleLoadMore}
itemContent={(_index, chat) => {
const chatSilence = chatSilences?.find((chatSilence) => String(chatSilence.target_account_id) === chat.account.id);
return (
<div className='px-2'>
<ChatListItem chat={chat} onClick={onClickChat} chatSilence={chatSilence} />
</div>
);
}}
components={{
ScrollSeekPlaceholder: () => <PlaceholderChat />,
Footer: () => hasNextPage ? <Spinner withText={false} /> : null,
EmptyPlaceholder: renderEmpty,
}}
/>
</PullToRefresh>
<>

View File

@ -0,0 +1,102 @@
import React from 'react';
import { VirtuosoMockContext } from 'react-virtuoso';
import { __stub } from 'soapbox/api';
import { ChatContext } from 'soapbox/contexts/chat-context';
import { StatProvider } from 'soapbox/contexts/stat-context';
import chats from 'soapbox/jest/fixtures/chats.json';
import { render, rootState, screen, waitFor } from 'soapbox/jest/test-helpers';
import { normalizeInstance } from 'soapbox/normalizers';
import ChatPane from '../chat-pane';
const renderComponentWithChatContext = (store = {}) => render(
<VirtuosoMockContext.Provider value={{ viewportHeight: 300, itemHeight: 100 }}>
<StatProvider>
<ChatContext.Provider value={{ isOpen: true }}>
<ChatPane />
</ChatContext.Provider>
</StatProvider>
</VirtuosoMockContext.Provider>,
undefined,
store,
);
const store = rootState
.set('instance', normalizeInstance({
version: '3.4.1 (compatible; TruthSocial 1.0.0)',
}));
describe('<ChatPane />', () => {
describe('when there are chats', () => {
beforeEach(() => {
__stub((mock) => {
mock.onGet('/api/v1/pleroma/chats').reply(200, chats, {
link: '<https://example.com/api/v1/pleroma/chats?since_id=2>; rel=\'prev\'',
});
});
});
it('renders the chats', async () => {
renderComponentWithChatContext();
await waitFor(() => {
expect(screen.getAllByTestId('chat-list-item')).toHaveLength(chats.length);
});
});
});
describe('when there are no chats', () => {
beforeEach(() => {
__stub((mock) => {
mock.onGet('/api/v1/pleroma/chats').reply(200, [], {
link: null,
});
});
});
it('renders the blankslate', async () => {
renderComponentWithChatContext();
await waitFor(() => {
expect(screen.getByTestId('chat-pane-blankslate')).toBeInTheDocument();
});
});
});
describe('when the software is Truth Social', () => {
beforeEach(() => {
__stub((mock) => {
mock.onGet('/api/v1/pleroma/chats').reply(200, chats, {
link: '<https://example.com/api/v1/pleroma/chats?since_id=2>; rel=\'prev\'',
});
});
});
it('renders the search input', async () => {
renderComponentWithChatContext(store);
await waitFor(() => {
expect(screen.getByTestId('chat-search-input')).toBeInTheDocument();
});
});
});
describe('when the software is not Truth Social', () => {
beforeEach(() => {
__stub((mock) => {
mock.onGet('/api/v1/pleroma/chats').reply(200, chats, {
link: '<https://example.com/api/v1/pleroma/chats?since_id=2>; rel=\'prev\'',
});
});
});
it('does not render the search input', async () => {
renderComponentWithChatContext();
await waitFor(() => {
expect(screen.queryAllByTestId('chat-search-input')).toHaveLength(0);
});
});
});
});

View File

@ -17,7 +17,12 @@ const Blankslate = ({ onSearch }: IBlankslate) => {
const intl = useIntl();
return (
<Stack alignItems='center' justifyContent='center' className='h-full flex-grow'>
<Stack
alignItems='center'
justifyContent='center'
className='h-full flex-grow'
data-testid='chat-pane-blankslate'
>
<Stack space={4}>
<Stack space={1} className='max-w-[80%] mx-auto'>
<Text size='lg' weight='bold' align='center'>

View File

@ -1,4 +1,3 @@
import sumBy from 'lodash/sumBy';
import React, { useState } from 'react';
import { Stack } from 'soapbox/components/ui';

View File

@ -22,6 +22,7 @@ const ChatSearchInput: React.FC<IChatSearchInput> = ({ value, onChange, onClear
return (
<Input
data-testid='chat-search-input'
type='text'
autoFocus
placeholder={intl.formatMessage(messages.searchPlaceholder)}

View File

@ -0,0 +1,62 @@
[
{
"id": "1",
"unread": 0,
"created_by_account": "2",
"last_message": {
"account_id": "2",
"chat_id": "85",
"content": "last message content",
"created_at": "2022-09-28T17:43:01.432Z",
"id": "1166",
"unread": false,
"discarded_at": "2022-09-29T19:09:30.253Z"
},
"created_at": "2022-08-26T14:49:16.360Z",
"updated_at": "2022-09-29T19:09:30.257Z",
"accepted": true,
"discarded_at": null,
"account": {
"id": "2",
"username": "leonard",
"acct": "leonard",
"display_name": "leonard",
"created_at": "2021-10-19T00:00:00.000Z",
"avatar": "original.jpg",
"avatar_static": "original.jpg",
"verified": false,
"accepting_messages": true,
"chats_onboarded": true
}
},
{
"id": "2",
"unread": 0,
"created_by_account": "3",
"last_message": {
"account_id": "3",
"chat_id": "125",
"content": "\u003cp\u003eInventore enim numquam nihil facilis nostrum eum natus provident quis veritatis esse dolorem praesentium rem cumque.\u003c/p\u003e",
"created_at": "2022-09-23T14:09:29.625Z",
"id": "1033",
"unread": false,
"discarded_at": null
},
"created_at": "2022-09-22T15:06:49.675Z",
"updated_at": "2022-09-23T14:09:29.628Z",
"accepted": true,
"discarded_at": null,
"account": {
"id": "3",
"username": "sheldon",
"acct": "sheldon",
"display_name": "sheldon",
"created_at": "2022-09-22T00:00:00.000Z",
"avatar": "original.jpg",
"avatar_static": "original.jpg",
"verified": false,
"accepting_messages": true,
"chats_onboarded": true
}
}
]