Skip to content

Commit 64ee40d

Browse files
committed
test(edit-profile): add form submission tests
1 parent a1c6096 commit 64ee40d

2 files changed

Lines changed: 65 additions & 1 deletion

File tree

src/__tests__/profile/edit_profile.test.tsx

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import * as ImagePicker from 'expo-image-picker';
1111
import { formatBirthDate } from '@/components/utils/profile';
1212
import { mockUsers } from '@/mocks/data/userMock';
1313
import EditProfileScreen from '@/screens/profile/EditProfileScreen';
14+
import { updateUserProfile } from '@/services/user';
1415
import { useUserStore } from '@/stores/userStore';
1516

1617
jest.mock('@/hooks/useTheme', () => ({
@@ -23,13 +24,15 @@ jest.mock('@react-navigation/elements', () => ({
2324

2425
const mockSetOptions = jest.fn();
2526

27+
const mockGoBack = jest.fn();
28+
2629
jest.mock('@react-navigation/native', () => {
2730
const actual = jest.requireActual('@react-navigation/native');
2831
return {
2932
...actual,
3033
useNavigation: () => ({
3134
navigate: jest.fn(),
32-
goBack: jest.fn(),
35+
goBack: mockGoBack,
3336
setOptions: mockSetOptions,
3437
}),
3538
};
@@ -319,4 +322,62 @@ describe('EditProfileScreen (adjusted)', () => {
319322
expect(ImagePicker.launchImageLibraryAsync).toHaveBeenCalled();
320323
});
321324
});
325+
326+
it('calls handleFormSubmit when header button is pressed', async () => {
327+
(updateUserProfile as jest.Mock).mockResolvedValueOnce({});
328+
329+
const { getByTestId } = render(
330+
<NavigationContainer>
331+
<QueryClientProvider client={mockQueryClient}>
332+
<EditProfileScreen />
333+
</QueryClientProvider>
334+
</NavigationContainer>
335+
);
336+
337+
// change something
338+
fireEvent.changeText(getByTestId('edit-bio-input'), 'New Bio');
339+
340+
// Extract the headerRight Button from setOptions
341+
expect(mockSetOptions).toHaveBeenCalled();
342+
const headerOptions = mockSetOptions.mock.calls[0][0];
343+
const headerRightButton = headerOptions.headerRight();
344+
345+
await act(async () => {
346+
headerRightButton.props.onPress();
347+
});
348+
await act(async () => {
349+
expect(mockGoBack).toHaveBeenCalled();
350+
});
351+
});
352+
353+
it('does not call handleFormSubmit when header button is pressed and form is invalid', async () => {
354+
(updateUserProfile as jest.Mock).mockResolvedValueOnce({});
355+
356+
const { getByTestId } = render(
357+
<NavigationContainer>
358+
<QueryClientProvider client={mockQueryClient}>
359+
<EditProfileScreen />
360+
</QueryClientProvider>
361+
</NavigationContainer>
362+
);
363+
364+
// Set invalid website
365+
await act(async () => {
366+
fireEvent.changeText(getByTestId('edit-website-input'), 'invalid-url');
367+
});
368+
369+
// Extract the latest headerRight button
370+
const headerOptions = mockSetOptions.mock.calls[mockSetOptions.mock.calls.length - 1][0];
371+
const headerRightButton = headerOptions.headerRight();
372+
373+
// The button should be disabled due to invalid form
374+
expect(headerRightButton.props.disabled).toBe(true);
375+
376+
// Try pressing it (won't call handleFormSubmit because disabled)
377+
await act(async () => {
378+
headerRightButton.props.onPress();
379+
});
380+
381+
expect(mockGoBack).not.toHaveBeenCalled();
382+
});
322383
});

src/screens/profile/EditProfileScreen.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ const EditProfileScreen = () => {
195195
}, [websiteError, birthDateError, error]);
196196

197197
const handleFormSubmit = useCallback(async () => {
198+
if (isError) return;
199+
198200
try {
199201
// clear any previous errors
200202
setError(null);
@@ -248,6 +250,7 @@ const EditProfileScreen = () => {
248250
bannerUrl,
249251
formDataChanged,
250252
queryClient,
253+
isError,
251254
]);
252255

253256
useEffect(() => {

0 commit comments

Comments
 (0)