wix / react-native-ui-lib

UI Components Library for React Native
https://wix.github.io/react-native-ui-lib/
MIT License
6.44k stars 706 forks source link

Issues with ThemeManager in Jest #778

Closed casconed closed 4 years ago

casconed commented 4 years ago

Using ThemeManager.setComponentTheme, when running tests modules which call that result in an error:

TypeError: Cannot read property 'setComponentTheme' of undefined

I've tried mocking react-native-ui-lib with no success.

ethanshar commented 4 years ago

Hey @casconed Can you share the your test file and how you're mocking RNUIlib so we can try to reproduce. Thanks

casconed commented 4 years ago

Initially, I wasn't mocking, but then we began running into issues with AccessiblityInfo. Eventually we settled on: jest.mock('react-native-ui-lib') (which is setup in a jest setup script)

The component in question:

import React, { useEffect, useState } from 'react'
import { View, TextField } from 'react-native-ui-lib'
import * as FoundationConfig from '../FoundationConfig' // eslint-disable-line no-unused-vars
import * as ComponentsConfig from '../ComponentsConfig' // eslint-disable-line no-unused-vars
import { parsePhoneNumberFromString, AsYouType } from 'libphonenumber-js'

const PhoneNumber = ({ phoneNumber, setPhoneNumber, setPhoneComplete }) => {
  const [showErrorMessage, setShowErrorMessage] = useState(false)

  useEffect(() => {
    if (phoneNumber.length === 14) {
      const phoneData = '+1' + phoneNumber
      const parsedNumber = parsePhoneNumberFromString(phoneData)
      const validNum =
        parsedNumber.country === 'US' && parsedNumber.isValid() === true

      if (validNum) {
        setPhoneComplete(true)
      } else {
        setPhoneComplete(false)
        setShowErrorMessage(true)
      }
    } else {
      setShowErrorMessage(false)
    }
  }, [phoneNumber])

  const formatNumber = number => {
    setPhoneNumber(number)
    const formattedNumber = new AsYouType('US').input(number)
    setPhoneNumber(formattedNumber)
  }

  return (
    <View marginT-20>
      <TextField
        autoFocus
        value={phoneNumber}
        onChangeText={text => formatNumber(text)}
        placeholder='(555) 555-5555'
        title='Phone Number'
        titleColor='black'
        error={
          showErrorMessage
            ? 'Please enter a valid phone number (U.S. only)'
            : undefined
        }
        underlineColor='rgba(60, 60, 67, 0.1)'
        keyboardType='number-pad'
        maxLength={14}
      />
    </View>
  )
}

export default PhoneNumber

and the test:

import React from 'react'
import renderer from 'react-test-renderer'
import Enzyme, { shallow } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import PhoneNumber from '../PhoneNumber'

Enzyme.configure({ adapter: new Adapter() })

beforeEach(() => {
  jest.restoreAllMocks()
  jest.resetAllMocks()
})

const mockSetAreaCode = jest.fn()
const props = {
  setPhoneComplete: jest.fn(),
  setAreaCode: mockSetAreaCode
}

it('renders correctly', () => {
  const tree = renderer.create(<PhoneNumber {...props} />).toJSON()

  expect(tree).toMatchSnapshot()
})

it('all 3 text inputs exist', () => {
  const wrapper = shallow(<PhoneNumber {...props} />)

  const areaCodeInput = wrapper.find({ testID: 'areaCodeInput' }).first()
  const prefixInput = wrapper.find({ testID: 'prefixInput' }).first()
  const lineInput = wrapper.find({ testID: 'lineInput' }).first()

  expect(areaCodeInput.exists()).toBe(true)
  expect(prefixInput.exists()).toBe(true)
  expect(lineInput.exists()).toBe(true)
})
ethanshar commented 4 years ago

@casconed Consider mocking accessibility API instead of react-native-ui-lib try mocking like this

jest.spyOn(AccessibilityInfo, 'isScreenReaderEnabled').mockImplementation(() => new Promise.resolve(false));

we also mock it in our jest-setup https://github.com/wix/react-native-ui-lib/blob/master/jest-setup.js

casconed commented 4 years ago

Thanks! That took care of that. I also had to add:

NativeModules.StatusBarManager = { getHeight: jest.fn() }

to resolve an error:

TypeError: StatusBarManager.getHeight is not a function

      at setStatusBarHeight (node_modules/react-native-ui-lib/src/helpers/Constants.js:22:26)
      at Object.<anonymous> (node_modules/react-native-ui-lib/src/helpers/Constants.js:127:1)
      at Object.<anonymous> (node_modules/react-native-ui-lib/src/style/typography.js:2:1)
ethanshar commented 4 years ago

yes, We will consider exporting out jest-setup so you can get our mocks