Ganda Rain Panjaitan
Ganda Rain Panjaitan

Reputation: 949

How to test Platform react-native with Jest?

I want to show apple button if platform is ios. The button show properly in ios emulator. But I am confused to test the platfrom. I have try to mock the platform but the platform will be ios by default in the first time (you can see the image).

This is my component.

import React, { useState, useEffect } from 'react'
import { ScrollView, StatusBar, Platform, View, Text, Linking, SafeAreaView } from 'react-native'
import Header from './components/Header'
import Form from './components/Form'
import ButtonFull from '../../../__global__/button/buttonFull'
import styles from './styles/StyleLogin'
import color from '../../../__global__/styles/themes/colorThemes'
const LoginScreen = () => {

  const showAppleButton = () => {
    console.log('Platform ', Platform.OS)
    if (Platform.OS === 'ios') {
      console.log('Platform OS ', Platform.OS)
      console.log('Platform Version ', Platform.Version)
      const version = Platform.Version ? Platform.Version.split('.')[0] : 0
      if (version >= 13) {
        return (
          <View style={styles.containerButton}>
            <ButtonFull
              accessibilityLabel={'appleButton'}
              isDisabled={false}
              buttonColor={color.black}
              onPress={() => loginWithApple()}
              title={'Apple ID'}
            />
          </View>
        )
      } else {
        return false
      }
    } else {
      return false
    }
  }

  return (
    <ScrollView>
      <StatusBar
        translucent
        backgroundColor="transparent"
        barStyle="light-content"
      />
      <Header />
      <Form
        phoneNumber={phoneNumber}
        changePhoneNumber={(value) => changePhoneNumber(value)}
        focus={focus}
        setFocus={(value) => setFocus(value)}
        loginSubmit={() => loginSubmit()}
        error={error}
        fullFilled={fullFilled}
        submited={submited}
        setSubmited={(value) => setSubmited(value)}
        sendOtp={() => sendOtp()} />
      {showAppleButton()}
    </ScrollView>
  )
}

export default LoginScreen

Test File

import React from 'react'
import { configure, shallow } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import LoginScreen from '../index'
import renderer from 'react-test-renderer'
import { fireEvent, render, waitFor } from 'react-native-testing-library'
import '@testing-library/jest-native/extend-expect'
import { Provider } from 'react-redux'
import reducers from '../../../../redux/store'
import { createStore } from 'redux'
import { Platform } from 'react-native'
jest.mock('@react-navigation/native', () => ({
  useNavigation: component => component,
}))

describe('Login screen', () => {
  const mockPlatform = (OS, Version) => {
    jest.resetModules()
    jest.doMock('react-native/Libraries/Utilities/Platform', () => ({
      OS,
      select: config => config[OS],
      Version,
    }))
  };

  const store = createStore(reducers)
  configure({ adapter: new Adapter() })
  const wrapper = shallow(<Provider store={store}><LoginScreen /></Provider>)
  const rendered = renderer.create(<Provider store={store}><LoginScreen /></Provider>)

  it('renders correctly', () => {
    expect(rendered.toJSON()).toBeTruthy()
  })

  it('should render the header component', () => {
    expect(wrapper.find('Header').exists())
  })

  it('should render the form component', () => {
    expect(wrapper.find('Form').exists())
  })

  it('should render the button social media', () => {
    mockPlatform('android', '15.0.1')
    console.log('Apple Button ', wrapper.find('[accessibilityLabel="appleButton"]').exists())
  })
})

In this image, platform will be ios in the first time. I dont know why. Test Result

Upvotes: 0

Views: 1819

Answers (1)

Estus Flask
Estus Flask

Reputation: 222309

It's not safe to rely on module internals like react-native/Libraries/Utilities/Platform. Platform is imported from react-native and should be preferably mocked on this module.

jest.doMock doesn't affect modules that were imported on top level. In order for a mock to take effect, the whole hierarchy that depends on mocked module needs to re-imported locally with require.

In this case this isn't needed because Platform is referred as an object, so its properties can be mocked instead. The mock needs to be aware which properties can be mocked as functions:

let originalOS;

beforeEach(() => {
  originalOS = Platform.OS;
});

afterEach(() => {
  Platform.OS = originalOS;
  jest.restoreAllMocks();
});

it('should mock Platform', () => {
  jest.spyOn(Platform, 'select').mockReturnValue('android');
  jest.spyOn(Platform, 'Version', 'get').mockReturnValue('15.0.1')
  Platform.OS = 'android';
  ...
});

Upvotes: 2

Related Questions