Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/__tests__/hooks/profile/useBlockMutation.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,6 @@ describe('useBlockMutation', () => {
expect(invalidateSpy).toHaveBeenCalledWith(
expect.objectContaining({ queryKey: ['following', 'viewer'] })
);

expect(invalidateSpy).toHaveBeenCalledWith(
expect.objectContaining({ queryKey: ['following-feed', 'viewer'], exact: true })
);
});

it('does not call updateConnectionsLists when block === previous (change === 0)', async () => {
Expand Down
27 changes: 6 additions & 21 deletions src/__tests__/hooks/profile/useFollowMutation.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ const mockUseUserStore = useUserStore as jest.MockedFunction<typeof useUserStore
};
mockUseUserStore.getState = jest.fn();

jest.mock('@/services/connections', () => ({
followUser: jest.fn(),
unfollowUser: jest.fn(),
getUserProfile: jest.fn(),
}));

const rel: UserProfile['relationship'] = {
blocking: false,
blockedBy: false,
Expand Down Expand Up @@ -534,27 +540,6 @@ describe('useFollowMutation', () => {
expect(revertedRetweeters.pages[0].data[0].relationship?.following).toBe(false);
});

it('handles mutation without target profile in cache', async () => {
const queryClient = createQueryClient();
const wrapper = createWrapper(queryClient);

const mockUpdateUser = jest.fn();
const viewerProfile = createProfile({ username: 'viewer', followingCount: 5 });
setUserStoreState({ user: viewerProfile, updateUser: mockUpdateUser });

mockFollowUser.mockResolvedValue({ success: true });

const { result } = renderHook(() => useFollowMutation(), { wrapper });

await act(async () => {
await result.current.mutateAsync({ username: 'unknownUser', follow: true, previous: false });
});

expect(mockUpdateUser).toHaveBeenCalledWith({ followingCount: 6 });

expect(queryClient.getQueryData(['profile', 'unknownUser'])).toBeUndefined();
});

it('handles unfollow mutation correctly with cache updates', async () => {
const { unfollowUser } = jest.requireMock('@/services/connections');
const queryClient = createQueryClient();
Expand Down
3 changes: 0 additions & 3 deletions src/__tests__/hooks/profile/useMuteMutation.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,5 @@ describe('useMuteMutation', () => {
expect(invalidateSpy).toHaveBeenCalledWith(
expect.objectContaining({ queryKey: ['profile', 'target'] })
);
expect(invalidateSpy).toHaveBeenCalledWith(
expect.objectContaining({ queryKey: ['following-feed', 'viewer'], exact: true })
);
});
});
8 changes: 8 additions & 0 deletions src/__tests__/profile/FollowingScreen.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ jest.mock('@/services/connections', () => ({
getUserFollowing: jest.fn(),
}));

jest.mock('@react-navigation/native', () => {
const actualNav = jest.requireActual('@react-navigation/native');
return {
...actualNav,
useFocusEffect: jest.fn().mockImplementation((callback) => callback()),
};
});

const mockQueryClient = new QueryClient({
defaultOptions: {
queries: { retry: false },
Expand Down
180 changes: 0 additions & 180 deletions src/__tests__/screens/profile/connections/FollowingScreen.test.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ import { navigationRef } from '@/navigation/navigationRef';
import BlockedAccountsScreen from '@/screens/settings/privacy/BlockedAccountsScreen';
import { PROFILE, ROOT } from '@/utils/navigation/routeNames';

jest.mock('@react-navigation/native', () => {
const actualNav = jest.requireActual('@react-navigation/native');
return {
...actualNav,
useFocusEffect: jest.fn().mockImplementation((callback) => callback()),
};
});

jest.mock('@/hooks/profile/useUserBlocks', () => ({ useUserBlocks: jest.fn() }));
jest.mock('@/hooks/profile/useBlockMutation', () => ({ useBlockMutation: jest.fn() }));
jest.mock('@/hooks/profile/useFollowMutation', () => ({ useFollowMutation: jest.fn() }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ import { navigationRef } from '@/navigation/navigationRef';
import MutedAccountsScreen from '@/screens/settings/privacy/MutedAccountsScreen';
import { PROFILE, ROOT } from '@/utils/navigation/routeNames';

jest.mock('@react-navigation/native', () => {
const actualNav = jest.requireActual('@react-navigation/native');
return {
...actualNav,
useFocusEffect: jest.fn().mockImplementation((callback) => callback()),
};
});
jest.mock('@/hooks/profile/useUserMutes', () => ({ useUserMutes: jest.fn() }));
jest.mock('@/hooks/profile/useBlockMutation', () => ({ useBlockMutation: jest.fn() }));
jest.mock('@/hooks/profile/useFollowMutation', () => ({ useFollowMutation: jest.fn() }));
Expand All @@ -32,8 +39,9 @@ const setPlatformOS = (os: typeof _initialOS) => {
};

describe('MutedAccountsScreen', () => {
const queryClient = new QueryClient();

const renderWithClient = (ui: ReactElement) => {
const queryClient = new QueryClient();
return render(ui, {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
Expand All @@ -42,6 +50,7 @@ describe('MutedAccountsScreen', () => {
};

beforeEach(() => {
queryClient.clear();
jest.clearAllMocks();

(useTheme as jest.Mock).mockReturnValue({ theme: 'light' });
Expand Down
3 changes: 2 additions & 1 deletion src/components/ui/TimelineFeedList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ export const MemoizedTweetItem = memo<{
a.retweetCount === b.retweetCount &&
a.replyCount === b.replyCount &&
(a.media?.length || 0) === (b.media?.length || 0) &&
!!a.quotedTweet === !!b.quotedTweet
!!a.quotedTweet === !!b.quotedTweet &&
a.author.relationship === b.author.relationship
);
}
);
Expand Down
11 changes: 8 additions & 3 deletions src/components/ui/TweetDrawer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useMemo } from 'react';
import { useCallback, useMemo, useState } from 'react';

import { Alert, StyleSheet, Text, TouchableOpacity, View } from 'react-native';

Expand Down Expand Up @@ -36,6 +36,8 @@ const TweetDrawer = ({ visible, onClose, author, onShowDeleteModal }: TweetDrawe
const isMuted = author.relationship?.muted ?? false;
const isFollowing = author.relationship?.following ?? false;

const [followingState, setFollowingState] = useState<boolean>(isFollowing);

const followMutation = useFollowMutation();
const blockMutation = useBlockMutation();
const muteMutation = useMuteMutation();
Expand Down Expand Up @@ -63,6 +65,9 @@ const TweetDrawer = ({ visible, onClose, author, onShowDeleteModal }: TweetDrawe
onError: (error) => {
Alert.alert('Unable to update follow', error?.message ?? 'Please try again.');
},
onSuccess: () => {
setFollowingState(shouldFollow);
},
}
);
},
Expand Down Expand Up @@ -159,13 +164,13 @@ const TweetDrawer = ({ visible, onClose, author, onShowDeleteModal }: TweetDrawe
testID="follow-button"
>
<MaterialCommunityIcons
name={isFollowing ? 'account-remove-outline' : 'account-plus-outline'}
name={followingState ? 'account-remove-outline' : 'account-plus-outline'}
size={25}
color={currentColors.mutedForeground}
/>
<AppText>
<Text>
{isFollowing ? `Unfollow @${author.username}` : `Follow @${author.username}`}
{followingState ? `Unfollow @${author.username}` : `Follow @${author.username}`}
</Text>
</AppText>
</TouchableOpacity>
Expand Down
Loading
Loading