diff --git a/app/soapbox/features/onboarding/steps/suggested-accounts-step.tsx b/app/soapbox/features/onboarding/steps/suggested-accounts-step.tsx index 8db08d1a4..a05202ff9 100644 --- a/app/soapbox/features/onboarding/steps/suggested-accounts-step.tsx +++ b/app/soapbox/features/onboarding/steps/suggested-accounts-step.tsx @@ -5,7 +5,7 @@ import { FormattedMessage } from 'react-intl'; import ScrollableList from 'soapbox/components/scrollable_list'; import { Button, Card, CardBody, Stack, Text } from 'soapbox/components/ui'; import AccountContainer from 'soapbox/containers/account_container'; -import useOnboardingSuggestions from 'soapbox/queries/suggestions'; +import { useOnboardingSuggestions } from 'soapbox/queries/suggestions'; const SuggestedAccountsStep = ({ onNext }: { onNext: () => void }) => { const { data, fetchNextPage, hasNextPage, isFetching } = useOnboardingSuggestions(); diff --git a/app/soapbox/features/placeholder/components/placeholder-sidebar-suggestions.tsx b/app/soapbox/features/placeholder/components/placeholder-sidebar-suggestions.tsx index 757c47cc7..e96268cb2 100644 --- a/app/soapbox/features/placeholder/components/placeholder-sidebar-suggestions.tsx +++ b/app/soapbox/features/placeholder/components/placeholder-sidebar-suggestions.tsx @@ -11,7 +11,7 @@ export default ({ limit }: { limit: number }) => { return ( <> {new Array(limit).fill(undefined).map((_, idx) => ( - +
({ + account_avatar: 'avatar', + account_id: id, + acct: 'acct', + display_name: 'my name', + note: 'hello', + verified: true, +}); + +const buildSuggestion = (id: string) => ({ + source: 'staff', + account: { + username: 'username', + verified: true, + id, + acct: 'acct', + avatar: 'avatar', + avatar_static: 'avatar', + display_name: 'my name', + }, +}); + describe('', () => { - it('renders suggested accounts', () => { - const store = { - accounts: ImmutableMap({ - '1': normalizeAccount({ - id: '1', - acct: 'username', - display_name: 'My name', - avatar: 'test.jpg', - }), - }), - suggestions: { - items: ImmutableOrderedSet([{ - source: 'staff', - account: '1', - }]), - }, - }; - - render(, undefined, store); - expect(screen.getByTestId('account')).toHaveTextContent(/my name/i); - }); + let store: any; - it('renders multiple accounts', () => { - const store = { - accounts: ImmutableMap({ - '1': normalizeAccount({ - id: '1', - acct: 'username', - display_name: 'My name', - avatar: 'test.jpg', - }), - '2': normalizeAccount({ - id: '1', - acct: 'username2', - display_name: 'My other name', - avatar: 'test.jpg', - }), - }), - suggestions: { - items: ImmutableOrderedSet([ - { - source: 'staff', - account: '1', - }, - { - source: 'staff', - account: '2', - }, - ]), - }, - }; - - render(, undefined, store); - expect(screen.queryAllByTestId('account')).toHaveLength(2); - }); + describe('using Truth Social software', () => { + beforeEach(() => { + store = rootState + .set('me', '1234') + .set('instance', normalizeInstance({ + version: '3.4.1 (compatible; TruthSocial 1.0.0)', + })); + }); + + describe('with a single suggestion', () => { + beforeEach(() => { + __stub((mock) => { + mock.onGet('/api/v1/truth/carousels/suggestions') + .reply(200, [buildTruthSuggestion('1')], { + link: '; rel=\'prev\'', + }); + }); + }); + + it('renders suggested accounts', async () => { + render(, undefined, store); + + await waitFor(() => { + expect(screen.getByTestId('account')).toHaveTextContent(/my name/i); + }); + }); + }); + + describe('with a multiple suggestion', () => { + beforeEach(() => { + __stub((mock) => { + mock.onGet('/api/v1/truth/carousels/suggestions') + .reply(200, [buildTruthSuggestion('1'), buildTruthSuggestion('2')], { + link: '; rel=\'prev\'', + }); + }); + }); + + it('renders suggested accounts', async () => { + render(, undefined, store); + + await waitFor(() => { + expect(screen.queryAllByTestId('account')).toHaveLength(2); + }); + }); + }); + + describe('with a set limit', () => { + beforeEach(() => { + __stub((mock) => { + mock.onGet('/api/v1/truth/carousels/suggestions') + .reply(200, [buildTruthSuggestion('1'), buildTruthSuggestion('2')], { + link: '; rel=\'prev\'', + }); + }); + }); + + it('respects the limit prop', async () => { + render(, undefined, store); - it('respects the limit prop', () => { - const store = { - accounts: ImmutableMap({ - '1': normalizeAccount({ - id: '1', - acct: 'username', - display_name: 'My name', - avatar: 'test.jpg', - }), - '2': normalizeAccount({ - id: '1', - acct: 'username2', - display_name: 'My other name', - avatar: 'test.jpg', - }), - }), - suggestions: { - items: ImmutableOrderedSet([ - { - source: 'staff', - account: '1', - }, - { - source: 'staff', - account: '2', - }, - ]), - }, - }; - - render(, undefined, store); - expect(screen.queryAllByTestId('account')).toHaveLength(1); + await waitFor(() => { + expect(screen.queryAllByTestId('account')).toHaveLength(1); + }); + }); + }); + + describe('when the API returns an empty list', () => { + beforeEach(() => { + __stub((mock) => { + mock.onGet('/api/v1/truth/carousels/suggestions') + .reply(200, [], { + link: '', + }); + }); + }); + + it('renders empty', async () => { + render(, undefined, store); + + await waitFor(() => { + expect(screen.queryAllByTestId('account')).toHaveLength(0); + }); + }); + }); }); - it('renders empty', () => { - const store = { - accounts: ImmutableMap({ - '1': normalizeAccount({ - id: '1', - acct: 'username', - display_name: 'My name', - avatar: 'test.jpg', - }), - '2': normalizeAccount({ - id: '1', - acct: 'username2', - display_name: 'My other name', - avatar: 'test.jpg', - }), - }), - suggestions: { - items: ImmutableOrderedSet([]), - }, - }; - - render(, undefined, store); - expect(screen.queryAllByTestId('account')).toHaveLength(0); + describe('using Pleroma software', () => { + beforeEach(() => { + store = rootState.set('me', '1234'); + }); + + describe('with a single suggestion', () => { + beforeEach(() => { + __stub((mock) => { + mock.onGet('/api/v2/suggestions') + .reply(200, [buildSuggestion('1')], { + link: '; rel=\'prev\'', + }); + }); + }); + + it('renders suggested accounts', async () => { + render(, undefined, store); + + await waitFor(() => { + expect(screen.getByTestId('account')).toHaveTextContent(/my name/i); + }); + }); + }); + + describe('with a multiple suggestion', () => { + beforeEach(() => { + __stub((mock) => { + mock.onGet('/api/v2/suggestions') + .reply(200, [buildSuggestion('1'), buildSuggestion('2')], { + link: '; rel=\'prev\'', + }); + }); + }); + + it('renders suggested accounts', async () => { + render(, undefined, store); + + await waitFor(() => { + expect(screen.queryAllByTestId('account')).toHaveLength(2); + }); + }); + }); + + describe('with a set limit', () => { + beforeEach(() => { + __stub((mock) => { + mock.onGet('/api/v2/suggestions') + .reply(200, [buildSuggestion('1'), buildSuggestion('2')], { + link: '; rel=\'prev\'', + }); + }); + }); + + it('respects the limit prop', async () => { + render(, undefined, store); + + await waitFor(() => { + expect(screen.queryAllByTestId('account')).toHaveLength(1); + }); + }); + }); + + describe('when the API returns an empty list', () => { + beforeEach(() => { + __stub((mock) => { + mock.onGet('/api/v2/suggestions') + .reply(200, [], { + link: '', + }); + }); + }); + + it('renders empty', async () => { + render(, undefined, store); + + await waitFor(() => { + expect(screen.queryAllByTestId('account')).toHaveLength(0); + }); + }); + }); }); }); diff --git a/app/soapbox/queries/__tests__/suggestions.test.ts b/app/soapbox/queries/__tests__/suggestions.test.ts index f38bf0dbc..aa352abe9 100644 --- a/app/soapbox/queries/__tests__/suggestions.test.ts +++ b/app/soapbox/queries/__tests__/suggestions.test.ts @@ -1,7 +1,7 @@ import { __stub } from 'soapbox/api'; import { renderHook, waitFor } from 'soapbox/jest/test-helpers'; -import useOnboardingSuggestions from '../suggestions'; +import { useOnboardingSuggestions } from '../suggestions'; describe('useCarouselAvatars', () => { describe('with a successful query', () => { @@ -17,7 +17,7 @@ describe('useCarouselAvatars', () => { }); }); - it('is successful', async() => { + it('is successful', async () => { const { result } = renderHook(() => useOnboardingSuggestions()); await waitFor(() => expect(result.current.isFetching).toBe(false)); @@ -33,7 +33,7 @@ describe('useCarouselAvatars', () => { }); }); - it('is successful', async() => { + it('is successful', async () => { const { result } = renderHook(() => useOnboardingSuggestions()); await waitFor(() => expect(result.current.isFetching).toBe(false)); diff --git a/app/soapbox/queries/suggestions.ts b/app/soapbox/queries/suggestions.ts index 8c9e2ec20..50b624831 100644 --- a/app/soapbox/queries/suggestions.ts +++ b/app/soapbox/queries/suggestions.ts @@ -4,7 +4,7 @@ import { fetchRelationships } from 'soapbox/actions/accounts'; import { importFetchedAccounts } from 'soapbox/actions/importer'; import { SuggestedProfile } from 'soapbox/actions/suggestions'; import { getLinks } from 'soapbox/api'; -import { useApi, useAppDispatch, useFeatures, useOwnAccount } from 'soapbox/hooks'; +import { useApi, useAppDispatch, useFeatures } from 'soapbox/hooks'; import { PaginatedResult, removePageItem } from '../utils/queries'; @@ -47,6 +47,10 @@ type TruthSuggestion = { verified: boolean } +type Result = TruthSuggestion | { + account: string +} + type PageParam = { link?: string } @@ -66,12 +70,11 @@ const mapSuggestedProfileToAccount = (suggestedProfile: SuggestedProfile) => ({ }); const useSuggestions = () => { - const account = useOwnAccount(); const api = useApi(); const dispatch = useAppDispatch(); const features = useFeatures(); - const getV2Suggestions = async(pageParam: PageParam): Promise> => { + const getV2Suggestions = async (pageParam: PageParam): Promise> => { const endpoint = pageParam?.link || '/api/v2/suggestions'; const response = await api.get(endpoint); const hasMore = !!response.headers.link; @@ -83,13 +86,13 @@ const useSuggestions = () => { dispatch(fetchRelationships(accountIds)); return { - result: response.data, + result: response.data.map(x => ({ ...x, account: x.account.id })), link: nextLink, hasMore, }; }; - const getTruthSuggestions = async(pageParam: PageParam): Promise> => { + const getTruthSuggestions = async (pageParam: PageParam): Promise> => { const endpoint = pageParam?.link || '/api/v1/truth/carousels/suggestions'; const response = await api.get(endpoint); const hasMore = !!response.headers.link; @@ -118,7 +121,6 @@ const useSuggestions = () => { ({ pageParam }: any) => getSuggestions(pageParam), { keepPreviousData: true, - enabled: !!account, getNextPageParam: (config) => { if (config?.hasMore) { return { nextLink: config?.link }; @@ -153,7 +155,7 @@ function useOnboardingSuggestions() { const api = useApi(); const dispatch = useAppDispatch(); - const getV2Suggestions = async(pageParam: any): Promise<{ data: Suggestion[], link: string | undefined, hasMore: boolean }> => { + const getV2Suggestions = async (pageParam: any): Promise<{ data: Suggestion[], link: string | undefined, hasMore: boolean }> => { const link = pageParam?.link || '/api/v2/suggestions'; const response = await api.get(link); const hasMore = !!response.headers.link; @@ -193,4 +195,4 @@ function useOnboardingSuggestions() { }; } -export { useOnboardingSuggestions as default, useSuggestions, useDismissSuggestion }; \ No newline at end of file +export { useOnboardingSuggestions, useSuggestions, useDismissSuggestion }; \ No newline at end of file