|
| 1 | +// userActions.integration.test.js |
| 2 | +import React from 'react'; |
| 3 | +import renderer, { act } from 'react-test-renderer'; |
| 4 | +import { ScrollView, View } from 'react-native'; |
| 5 | +import { Provider as StoreProvider } from 'react-redux'; |
| 6 | +import { Provider as PaperProvider } from 'react-native-paper'; |
| 7 | +import { SafeAreaProvider } from 'react-native-safe-area-context'; |
| 8 | +import { SafeAreaView } from "react-native"; |
| 9 | +import { NavigationContainer, useNavigation } from '@react-navigation/native'; |
| 10 | + |
| 11 | + |
| 12 | +import { render, screen, fireEvent, waitFor, getByText } from '@testing-library/react-native'; |
| 13 | +import { Provider } from 'react-redux'; |
| 14 | +import configureMockStore from 'redux-mock-store'; |
| 15 | +import thunk from 'redux-thunk'; |
| 16 | +import App from '../../App'; // Assuming App is the root component |
| 17 | +import AppHeader from '../../src/components/AppHeader'; |
| 18 | + |
| 19 | +import AppTheme from '../../src/constants/themes'; |
| 20 | + |
| 21 | +import { |
| 22 | + startLogout, |
| 23 | + startUpdateProfile, |
| 24 | + startUpdateUserData, |
| 25 | + startLoadUserData, |
| 26 | +} from '../../src/actions/userActions'; |
| 27 | + |
| 28 | +const middlewares = [thunk]; |
| 29 | +const mockStore = configureMockStore(middlewares); |
| 30 | + |
| 31 | + |
| 32 | +jest.mock('../../src/utils/localStorage.js', () => ({ |
| 33 | + AsyncStorage: jest.fn(), |
| 34 | + storeUID: jest.fn(), |
| 35 | + })); |
| 36 | + |
| 37 | +jest.mock('../../firebaseConfig', () => ({ |
| 38 | + auth: { |
| 39 | + signOut: jest.fn(() => Promise.resolve()), |
| 40 | + currentUser: { |
| 41 | + displayName: 'John Doe', |
| 42 | + }, |
| 43 | + }, |
| 44 | +})); |
| 45 | + |
| 46 | +jest.mock('firebase/auth', () => ({ |
| 47 | + createUserWithEmailAndPassword: jest.fn(), |
| 48 | + updateEmail: jest.fn(), |
| 49 | + signInWithEmailAndPassword: jest.fn(), |
| 50 | + updateProfile: jest.fn(() => Promise.resolve()), |
| 51 | + sendPasswordResetEmail: jest.fn(), |
| 52 | +})); |
| 53 | + |
| 54 | +// jest.mock('firebase/firestore', () => ({ |
| 55 | +// collection: jest.fn(), |
| 56 | +// addDoc: jest.fn(), |
| 57 | +// setDoc: jest.fn(), |
| 58 | +// doc: jest.fn(), |
| 59 | +// updateDoc: jest.fn(), |
| 60 | +// getDoc: jest.fn(), |
| 61 | +// })); |
| 62 | +jest.mock('firebase/firestore', () => ({ |
| 63 | + collection: jest.fn(() => ({ add: jest.fn() })), |
| 64 | + addDoc: jest.fn(), |
| 65 | + setDoc: jest.fn(), |
| 66 | + doc: jest.fn(() => ({ setDoc: jest.fn() })), |
| 67 | + updateDoc: jest.fn(), |
| 68 | + getDoc: jest.fn().mockReturnValue({ |
| 69 | + exists: jest.fn().mockReturnValue(true), // Mock 'exists' as a function |
| 70 | + data: jest.fn().mockReturnValue({ |
| 71 | + height: "6541", |
| 72 | + weight: "55", |
| 73 | + age: "666", |
| 74 | + gender: "male", |
| 75 | + sports: "running", |
| 76 | + dob: { |
| 77 | + seconds: 1627852800, // Example timestamp for July 2, 2021 |
| 78 | + nanoseconds: 0, // Firestore Timestamps include nanoseconds, but it's often okay to mock them as 0 in tests |
| 79 | + }, |
| 80 | + }), // Mock 'data' as a function |
| 81 | + }), |
| 82 | + })); |
| 83 | + |
| 84 | + |
| 85 | +jest.mock('react-native-vector-icons/MaterialIcons', () => require('../__mocks__/react-native-vector-icons.js').MaterialIcons); |
| 86 | +jest.mock('react-native-vector-icons/FontAwesome5', () => require('../__mocks__/react-native-vector-icons.js').FontAwesome5); |
| 87 | +jest.mock('@shopify/react-native-skia', () => require('../__mocks__/@shopify__react-native-skia.js')); |
| 88 | +jest.mock('../../src/components/visualizations/ActivityRings/Ring.jsx', () => { |
| 89 | + return jest.fn(({ ring, center, strokeWidth, scale }) => ( |
| 90 | + <div> |
| 91 | + Mock Ring Component - {ring.size}, {center.x}, {center.y}, {strokeWidth}, {scale} |
| 92 | + </div> |
| 93 | + )); |
| 94 | +}); |
| 95 | +jest.mock('victory-native', () => { |
| 96 | + // Mock the specific components and functionalities you use |
| 97 | + const MockBar = () => <div>Mock Bar</div>; |
| 98 | + const MockCartesianChart = () => <div>Mock CartesianChart</div>; |
| 99 | + const MockUseChartPressState = () => ({ /* Mock return value */ }); |
| 100 | + |
| 101 | + return { |
| 102 | + Bar: MockBar, |
| 103 | + CartesianChart: MockCartesianChart, |
| 104 | + useChartPressState: MockUseChartPressState, |
| 105 | + }; |
| 106 | +}); |
| 107 | +// jest.mock('../../src/actions/appActions', () => ({ |
| 108 | +// userMetricsDataModalVisible: jest.fn().mockReturnValue({ |
| 109 | +// type: 'USER_METRICS_DATA_MODAL_VISIBLE', |
| 110 | +// payload: { |
| 111 | +// visibility: false, |
| 112 | +// isFromSignUpScreen: false, |
| 113 | +// }}), |
| 114 | +// })); |
| 115 | + |
| 116 | +// Mocks ViewSleepData |
| 117 | +jest.mock('d3', () => ({ |
| 118 | + scaleLinear: jest.fn().mockReturnValue({ |
| 119 | + domain: jest.fn().mockReturnThis(), |
| 120 | + range: jest.fn().mockReturnThis(), |
| 121 | + ticks: jest.fn().mockReturnValue([0, 50, 100, 150, 200]), |
| 122 | + }), |
| 123 | + tickStep: jest.fn().mockReturnValue(50), |
| 124 | + ticks: jest.fn().mockReturnValue([0, 50, 100, 150, 200]), |
| 125 | +})); |
| 126 | + |
| 127 | +jest.mock('expo-font'); |
| 128 | +jest.mock('../../assets', () => ({ |
| 129 | + AppFontsResource: {}, |
| 130 | +})); |
| 131 | + |
| 132 | +jest.mock('@react-navigation/native', () => { |
| 133 | + const actualNav = jest.requireActual('@react-navigation/native'); |
| 134 | + return { |
| 135 | + ...actualNav, |
| 136 | + useNavigation: () => ({ |
| 137 | + navigate: jest.fn(), |
| 138 | + goBack: jest.fn(), |
| 139 | + }), |
| 140 | + useRoute: () => ({ |
| 141 | + name: 'Previous Screen', |
| 142 | + }), |
| 143 | + }; |
| 144 | + }); |
| 145 | + |
| 146 | + |
| 147 | + |
| 148 | + |
| 149 | +const initialState = { |
| 150 | + auth: { |
| 151 | + uid: '123', |
| 152 | + displayName: 'John Doe', |
| 153 | + }, |
| 154 | + user: { |
| 155 | + profile: {}, |
| 156 | + metrics: {}, |
| 157 | + }, |
| 158 | +}; |
| 159 | + |
| 160 | +describe('User Actions Integration Test', () => { |
| 161 | + let store; |
| 162 | + |
| 163 | + beforeEach(() => { |
| 164 | + store = mockStore(initialState); |
| 165 | + }); |
| 166 | + |
| 167 | + it('should log out the user', async () => { |
| 168 | + store.dispatch = jest.fn(store.dispatch); |
| 169 | + |
| 170 | + const { getByTestId, queryByText, getAllByTestId, getByText, getAllByRole, debug } = render( |
| 171 | + <Provider store={store}> |
| 172 | + <PaperProvider > |
| 173 | + <NavigationContainer> |
| 174 | + <View> |
| 175 | + <AppHeader title={"Test Title"} menu = {true} /> |
| 176 | + </View> |
| 177 | + </NavigationContainer> |
| 178 | + </PaperProvider> |
| 179 | + </Provider> |
| 180 | + ); |
| 181 | + |
| 182 | + debug(); // Log the rendered output to inspect the component tree |
| 183 | + |
| 184 | + const menuButton = getByTestId("menu-action"); |
| 185 | + |
| 186 | + await act(() => { |
| 187 | + fireEvent.press(menuButton); |
| 188 | + }); |
| 189 | + |
| 190 | + await waitFor(() => { |
| 191 | + expect(queryByText('Edit Profile')).not.toBeNull(); |
| 192 | + expect(queryByText('Settings & Privacy')).not.toBeNull(); |
| 193 | + expect(queryByText('Accessibility')).not.toBeNull(); |
| 194 | + expect(queryByText('Logout')).not.toBeNull(); |
| 195 | + }); |
| 196 | + |
| 197 | + const signOutButton = getByTestId("sign-out-button") |
| 198 | + await act(() => { |
| 199 | + fireEvent.press(signOutButton); |
| 200 | + }); |
| 201 | + |
| 202 | + let confirmSignOutButton |
| 203 | + await waitFor(() => { |
| 204 | + confirmSignOutButton = getByTestId("yes-sign-out-button") |
| 205 | + }) |
| 206 | + await act(() => { |
| 207 | + fireEvent.press(confirmSignOutButton); |
| 208 | + }); |
| 209 | + |
| 210 | + await waitFor(() => { |
| 211 | + expect(store.dispatch).toHaveBeenCalledWith(expect.any(Function)); |
| 212 | + const actions = store.getActions(); |
| 213 | + expect(actions).toContainEqual({ type: 'LOGOUT' }); |
| 214 | + expect(actions).toContainEqual({ type: 'showErrorToast', payload: 'User logged out!' }); |
| 215 | + }); |
| 216 | + }); |
| 217 | + |
| 218 | +// it('should update the user profile', async () => { |
| 219 | +// store.dispatch = jest.fn(store.dispatch); |
| 220 | + |
| 221 | +// render( |
| 222 | +// <Provider store={store}> |
| 223 | +// <App /> |
| 224 | +// </Provider> |
| 225 | +// ); |
| 226 | + |
| 227 | +// const updateProfileButton = screen.getByText(/update profile/i); |
| 228 | +// fireEvent.click(updateProfileButton); |
| 229 | + |
| 230 | +// await waitFor(() => { |
| 231 | +// expect(store.dispatch).toHaveBeenCalledWith(expect.any(Function)); |
| 232 | +// const actions = store.getActions(); |
| 233 | +// expect(actions).toContainEqual({ |
| 234 | +// type: 'UPDATE_PROFILE', |
| 235 | +// payload: ['John', 'Doe'], |
| 236 | +// }); |
| 237 | +// }); |
| 238 | +// }); |
| 239 | + |
| 240 | +// it('should update user data', async () => { |
| 241 | +// store.dispatch = jest.fn(store.dispatch); |
| 242 | + |
| 243 | +// render( |
| 244 | +// <Provider store={store}> |
| 245 | +// <App /> |
| 246 | +// </Provider> |
| 247 | +// ); |
| 248 | + |
| 249 | +// const updateUserDataButton = screen.getByText(/update user data/i); |
| 250 | +// fireEvent.click(updateUserDataButton); |
| 251 | + |
| 252 | +// await waitFor(() => { |
| 253 | +// expect(store.dispatch).toHaveBeenCalledWith(expect.any(Function)); |
| 254 | +// const actions = store.getActions(); |
| 255 | +// expect(actions).toContainEqual({ |
| 256 | +// type: 'UPDATE_USER_METRICS_DATA', |
| 257 | +// payload: { /* your user metrics data here */ }, |
| 258 | +// }); |
| 259 | +// }); |
| 260 | +// }); |
| 261 | + |
| 262 | +// it('should load user data', async () => { |
| 263 | +// store.dispatch = jest.fn(store.dispatch); |
| 264 | + |
| 265 | +// render( |
| 266 | +// <Provider store={store}> |
| 267 | +// <App /> |
| 268 | +// </Provider> |
| 269 | +// ); |
| 270 | + |
| 271 | +// const loadUserDataButton = screen.getByText(/load user data/i); |
| 272 | +// fireEvent.click(loadUserDataButton); |
| 273 | + |
| 274 | +// await waitFor(() => { |
| 275 | +// expect(store.dispatch).toHaveBeenCalledWith(expect.any(Function)); |
| 276 | +// const actions = store.getActions(); |
| 277 | +// // You can add more detailed expectations here based on what the action does |
| 278 | +// }); |
| 279 | +// }); |
| 280 | + |
| 281 | + |
| 282 | +}); |
0 commit comments