diff --git a/app/navigators/AppNavigator.js b/app/navigators/AppNavigator.js index d3baa1c..b03dff6 100644 --- a/app/navigators/AppNavigator.js +++ b/app/navigators/AppNavigator.js @@ -3,7 +3,7 @@ import { createStackNavigator } from '@react-navigation/stack'; import SplashScreen from '@scenes/SplashScreen/'; import ExampleScreen from '@scenes/ExampleScreen'; import { NavigationContainer } from '@react-navigation/native'; -import NavigationService from '../services/NavigationService'; +import { setTopLevelNavigator } from '../services/NavigationService'; const Stack = createStackNavigator(); /** * The root screen contains the application's navigation. @@ -12,7 +12,7 @@ const Stack = createStackNavigator(); */ export default function AppNavigator() { return ( - + diff --git a/app/scenes/RootScreen/index.js b/app/scenes/RootScreen/index.js index 122c23f..93f16f3 100644 --- a/app/scenes/RootScreen/index.js +++ b/app/scenes/RootScreen/index.js @@ -1,11 +1,10 @@ import { connect } from 'react-redux'; import { PropTypes } from 'prop-types'; -import NavigationService from '@services/NavigationService'; import AppNavigator from '@navigators/AppNavigator'; import Container from '@atoms/Container'; - import { rootScreenActions } from './reducer'; import React, { useEffect } from 'react'; +import { setRefForTopLevelNavigtor } from '@app/services/NavigationService'; const RootScreen = props => { useEffect(() => { @@ -13,10 +12,6 @@ const RootScreen = props => { props.startup(); }, []); - const setRefForTopLevelNavigtor = navigatorRef => { - NavigationService.setTopLevelNavigator(navigatorRef); - }; - return ( diff --git a/app/scenes/RootScreen/saga.js b/app/scenes/RootScreen/saga.js index 098f16e..a988d24 100644 --- a/app/scenes/RootScreen/saga.js +++ b/app/scenes/RootScreen/saga.js @@ -1,12 +1,12 @@ import { takeLatest } from 'redux-saga/effects'; -import NavigationService from '@app/services/NavigationService'; +import { navigateAndReset } from '@app/services/NavigationService'; import { rootScreenTypes } from './reducer'; /** * The startup saga is the place to define behavior to execute when the application starts. */ export function* startup() { - setTimeout(() => NavigationService.navigateAndReset('MainScreen'), 1000); + setTimeout(() => navigateAndReset('MainScreen'), 1000); } /** diff --git a/app/scenes/RootScreen/tests/saga.test.js b/app/scenes/RootScreen/tests/saga.test.js index f8ce417..c743c43 100644 --- a/app/scenes/RootScreen/tests/saga.test.js +++ b/app/scenes/RootScreen/tests/saga.test.js @@ -1,3 +1,4 @@ +/* eslint-disable sonarjs/no-duplicate-string */ /** * Test sagas */ @@ -5,12 +6,22 @@ /* eslint-disable redux-saga/yield-effects */ import { takeLatest } from 'redux-saga/effects'; -import NavigationService from 'app/services/NavigationService'; +// import NavigationService from 'app/services/NavigationService'; +import { navigateAndReset } from '@app/services/NavigationService'; import { timeout } from 'app/utils/testUtils'; import rootScreenSaga, { startup } from '../saga'; import { rootScreenTypes } from '../reducer'; import set from 'lodash/set'; + +const NavigationService = '@app/services/NavigationService'; +jest.mock('@app/services/NavigationService', () => ({ + ...jest.requireActual('@app/services/NavigationService'), + navigateAndReset: jest.fn() +})); describe('Tests for RootScreen sagas', () => { + afterEach(() => { + jest.clearAllMocks(); + }); const setupTests = () => ({ generator: rootScreenSaga(), submitSpy: jest.fn() @@ -25,15 +36,10 @@ describe('Tests for RootScreen sagas', () => { it('should ensure that the navigation service is called after waiting for 1000ms', async () => { const method = startup(); - NavigationService.setTopLevelNavigator({ dispatch: () => {} }); - const navigateAndResetSpy = jest.spyOn( - NavigationService, - 'navigateAndReset' - ); method.next(); await timeout(1000); - expect(navigateAndResetSpy).toHaveBeenCalled(); - expect(navigateAndResetSpy).toHaveBeenCalledWith('MainScreen'); + expect(navigateAndReset).toHaveBeenCalled(); + expect(navigateAndReset).toHaveBeenCalledWith('MainScreen'); }); it('should ensure that the navigation service is called after waiting for 1000ms', async () => { diff --git a/app/services/NavigationService.js b/app/services/NavigationService.js index 467c8ac..7b5ae4b 100644 --- a/app/services/NavigationService.js +++ b/app/services/NavigationService.js @@ -50,8 +50,4 @@ function navigateAndReset(routeName, params) { ); } -export default { - navigate, - navigateAndReset, - setTopLevelNavigator -}; +export { navigate, navigateAndReset, setTopLevelNavigator }; diff --git a/app/services/UserService.test.js b/app/services/tests/UserService.test.js similarity index 94% rename from app/services/UserService.test.js rename to app/services/tests/UserService.test.js index 53cbead..a8155f7 100644 --- a/app/services/UserService.test.js +++ b/app/services/tests/UserService.test.js @@ -1,6 +1,6 @@ import MockAdapter from 'axios-mock-adapter'; import { getApiClient } from 'app/utils/apiUtils'; -import { getUser } from './UserService'; +import { getUser } from '../UserService'; describe('UserService tests', () => { it('should make the api call to "/quotes?count=1"', async () => { diff --git a/app/services/tests/navigate.test.js b/app/services/tests/navigate.test.js new file mode 100644 index 0000000..fea5a93 --- /dev/null +++ b/app/services/tests/navigate.test.js @@ -0,0 +1,32 @@ +import { navigate, setTopLevelNavigator } from '../NavigationService'; +import { NavigationActions } from '@react-navigation/compat'; +jest.mock('@react-navigation/compat', () => ({ + NavigationActions: { + navigate: jest.fn() + } +})); +const navigatorRef = { goBack: 'goBack', dispatch: jest.fn() }; +setTopLevelNavigator(navigatorRef); +describe('navigate', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('dispatches navigation action with the correct routeName and params', () => { + const routeName = '/test'; + const params = { screen: 'MainScreen' }; + NavigationActions.navigate.mockReturnValueOnce({ + type: 'NAVIGATE_ACTION', + payload: { routeName, params } + }); + navigate(routeName, params); + expect(NavigationActions.navigate).toHaveBeenCalledWith({ + routeName, + params + }); + expect(navigatorRef.dispatch).toHaveBeenCalledWith({ + type: 'NAVIGATE_ACTION', + payload: { routeName, params } + }); + }); +}); diff --git a/app/services/tests/navigateAndReset.test.js b/app/services/tests/navigateAndReset.test.js new file mode 100644 index 0000000..0a0df12 --- /dev/null +++ b/app/services/tests/navigateAndReset.test.js @@ -0,0 +1,34 @@ +import { setTopLevelNavigator, navigateAndReset } from '../NavigationService'; +import { StackActions } from '@react-navigation/compat'; + +jest.mock('@react-navigation/compat', () => ({ + StackActions: { + replace: jest.fn() + } +})); +const navigatorRef = { goBack: 'goBack', dispatch: jest.fn() }; +setTopLevelNavigator(navigatorRef); +describe('test navigateAndReset', () => { + afterEach(() => { + // Reset mocks after each test + jest.clearAllMocks(); + }); + + it('dispatches stack action with the correct routeName and params', () => { + const routeName = '/test'; + const params = { screen: 'MainScreen' }; + StackActions.replace.mockReturnValueOnce({ + type: 'NAVIGATE_ACTION', + payload: { routeName, params } + }); + navigateAndReset(routeName, params); + expect(StackActions.replace).toHaveBeenCalledWith({ + routeName, + params + }); + expect(navigatorRef.dispatch).toHaveBeenCalledWith({ + type: 'NAVIGATE_ACTION', + payload: { routeName, params } + }); + }); +}); diff --git a/app/services/tests/setTopLevelNavigation.test.js b/app/services/tests/setTopLevelNavigation.test.js new file mode 100644 index 0000000..dcf2aa1 --- /dev/null +++ b/app/services/tests/setTopLevelNavigation.test.js @@ -0,0 +1,20 @@ +import set from 'lodash/set'; +import { setTopLevelNavigator } from '../NavigationService'; +jest.mock('lodash/set', () => jest.fn()); +describe('setTopLevelNavigator', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + it('sets the navigator object with the provided reference', () => { + const navigatorObject = { + navigator: null + }; + const navigatorRef = { goBack: 'goBack' }; + setTopLevelNavigator(navigatorRef); + expect(set).toHaveBeenCalledWith( + navigatorObject, + 'navigator', + navigatorRef + ); + }); +});