Skip to content

getByText fails with react-intl FormattedMessage #307

Closed
@alexborton

Description

@alexborton

react-native-testing-library @ ^1.13.2
react @ 16.9.0
react-test-renderer @ ^16.9.0
react-native @ https://github.com/expo/react-native/archive/sdk-36.0.0.tar.gz (I believe this is v0.60)

I have updated to react-intl @ ^3.12.1 from 2.x.x and now my native tests are failing at any getByText assertions. It throws a No instances found error.

If i debug() i can clearly see the text i am searching for in the console :(

react-intl uses <FormattedMessage ... /> to render translations, so i mock add the <IntlProvider /> to my custom render. The setup looks like this;

// reactNativeTestingLibrary/index.js
import { IntlProvider } from 'react-intl'

...

const customRender = (ui, options = {}) =>
  render(
    <Provider store={store}>
      <IntlProvider locale="en" textComponent={Text}>
        <ActionSheetProvider>
          <SafeAreaProvider
            initialSafeAreaInsets={{ top: 1, left: 2, right: 3, bottom: 4 }}
          >
            {ui}
          </SafeAreaProvider>
        </ActionSheetProvider>
      </IntlProvider>
    </Provider>,
    options,
  )

...
// componentToText/index.js

import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage } from 'react-intl'
import { Text } from 'native/components'

import messages from './messages'

const ChargeExpense = ({ type, reason }) => (
  <React.Fragment>
    <Text bold>
      <FormattedMessage
        {...messages.expenseType}
        values={{ TYPE: <Text bold={false}>{type || '-'}</Text> }}
      />
    </Text>
    <Text bold>
      <FormattedMessage
        {...messages.expenseReason}
        values={{ REASON: <Text bold={false}>{reason || '-'}</Text> }}
      />
    </Text>
  </React.Fragment>
)

ChargeExpense.propTypes = {
  type: PropTypes.string,
  reason: PropTypes.string,
}

export default ChargeExpense

// test.js

import React from 'react'
import { customRender as render } from 'reactNativeTestingLibrary'

...
import ChargeExpense from '..'

const { expenseType, expenseReason } = mockChargeExpense

describe('<ChargeExpense />', () => {
  it('renders an Expense type and Expense reason', () => {
    const { getByText, unmount, debug } = render(
      <ChargeExpense type={expenseType} reason={expenseReason} />,
    )

    debug()

    expect(getByText(/Expense type:/))
    expect(getByText(/Type of/))
    expect(getByText(/Expense reason:/))
    expect(getByText(/Reason for/))
    unmount()
  })

  it('renders type or reason as "-" when either are not defined', () => {
    const { getByText, getAllByText, unmount } = render(<Component />)

    expect(getByText(/Expense type:/))
    expect(getByText(/Expense reason:/))
    expect(getAllByText(/-/).length).toEqual(2)
    unmount()
  })
})
<ChargeExpense />
    ✕ renders an Expense type and Expense reason (67ms)
    ✕ renders type or reason as "-" when either are not defined (5ms)

  ● <ChargeExpense /> › renders an Expense type and Expense reason

    No instances found

      15 |     debug()
      16 | 
    > 17 |     expect(getByText(/Expense type:/))
         |            ^
      18 |     expect(getByText(/Type of/))
      19 |     expect(getByText(/Expense reason:/))
      20 |     expect(getByText(/Reason for/))

...

● <ChargeExpense /> › renders type or reason as "-" when either are not defined

    No instances found

      25 |     const { getByText, getAllByText, unmount } = render(<ChargeExpense />)
      26 | 
    > 27 |     expect(getByText(/Expense type:/))
         |            ^
      28 |     expect(getByText(/Expense reason:/))
      29 |     expect(getAllByText(/-/).length).toEqual(2)
      30 |     unmount()
// debug() output...

console.log
    <View
      style={
        Object {
          "flex": 1,
        }
      }
    >
      <RNCSafeAreaView
        onInsetsChange={[Function anonymous]}
        style={
          Object {
            "flex": 1,
          }
        }
      >
        <Text
          bold={true}
          className="sc-bdVaJa iFrGAG"
        >
          <Text>
            Expense type: 
            <Text
              bold={false}
              className="sc-bdVaJa hPmtWS"
            >
              Type of
            </Text>
          </Text>
        </Text>
        <Text
          bold={true}
          className="sc-bdVaJa iFrGAG"
        >
          <Text>
            Expense reason: 
            <Text
              bold={false}
              className="sc-bdVaJa hPmtWS"
            >
              Reason for
            </Text>
          </Text>
        </Text>
      </RNCSafeAreaView>
    </View>

      at debugDeep (node_modules/react-native-testing-library/build/helpers/debugDeep.js:1:530)

If i replace the <FormattedMessage /> with a <Text /> component, the text is found as expected... not sure how the FormattedMessage is able to obfuscate the result somehow, but still allow the text to be logged in the in the debug.

Apologies if this is a react-intl issue...

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions