Giter Club home page Giter Club logo

jest-native's Introduction

Caution

This package is deprecated and is no longer actively maintained.

We encourage you to migrate to React Native Testing Library, v12.4 or later, which includes modern built-in Jest matchers based on the matchers for this repository.

The migration process should be relatively straightforward, we have a migration guide available.

jest-native

eagle

Custom jest matchers to test the state of React Native.


version Code Coverage Build downloads PRs Welcome Discord Star on GitHub

Table of Contents

The problem

You want to use jest to write tests that assert various things about the state of a React Native app. As part of that goal, you want to avoid all the repetitive patterns that arise in doing so like checking for a native element's props, its text content, its styles, and more.

This solution

The jest-native library provides a set of custom jest matchers that you can use to extend jest. These will make your tests more declarative, clear to read and to maintain.

Compatibility

These matchers should, for the most part, be agnostic enough to work with any React Native testing utilities, but they are primarily intended to be used with React Native Testing Library. Any issues raised with existing matchers or any newly proposed matchers must be viewed through compatibility with that library and its guiding principles first.

Installation

This module should be installed as one of your project's devDependencies:

Using yarn

yarn add --dev @testing-library/jest-native

Using npm

npm install --save-dev @testing-library/jest-native

You will need react-test-renderer, react, and react-native installed in order to use this package.

Usage

Extending Jest matchers

Import @testing-library/jest-native/extend-expect once (for instance in your tests setup file) and you're good to go:

import '@testing-library/jest-native/extend-expect';

Alternatively, you can selectively import only the matchers you intend to use, and extend jest's expect yourself:

import { toBeEmptyElement, toHaveTextContent } from '@testing-library/jest-native';

expect.extend({ toBeEmptyElement, toHaveTextContent });

TypeScript support

In order to setup proper TypeScript type checking use either one of the following approches.

1. Use TypeScript Jest setup file.

Use jest-setup.ts file (instead of jest-setup.js file) which is added to Jest config's setupFilesAfterEnv option.

The Jest setup file should contain following line:

import '@testing-library/jest-native/extend-expect';

This should enable TypeScript checkign for both tsc and VS Code intellisense.

2. Use declarations.d.ts file

Alternatively, create declarations.d.ts file at the root level of your project, if it does not exist already.

Add following line at the top of your declarations.d.ts:

/// <reference types="@testing-library/jest-native" />

This should enable TypeScript checkign for both tsc and VS Code intellisense.

Matchers

jest-native has only been tested to work with React Native Testing Library. Keep in mind that these queries are intended only to work with elements corresponding to host components.

toBeDisabled

toBeDisabled();

Check whether or not an element is disabled from a user perspective.

This matcher will check if the element or its parent has any of the following props :

  • disabled
  • accessibilityState={{ disabled: true }}
  • editable={false} (for TextInput only)

Examples

const { getByTestId } = render(
  <View>
    <Button disabled testID="button" title="submit" onPress={(e) => e} />
    <TextInput accessibilityState={{ disabled: true }} testID="input" value="text" />
  </View>,
);

expect(getByTestId('button')).toBeDisabled();
expect(getByTestId('input')).toBeDisabled();

toBeEnabled

toBeEnabled();

Check whether or not an element is enabled from a user perspective.

Works similarly to expect().not.toBeDisabled().

Examples

const { getByTestId } = render(
  <View>
    <Button testID="button" title="submit" onPress={(e) => e} />
    <TextInput testID="input" value="text" />
  </View>,
);

expect(getByTestId('button')).toBeEnabled();
expect(getByTestId('input')).toBeEnabled();

toBeEmptyElement

toBeEmptyElement();

Check that the given element has no content.

Examples

const { getByTestId } = render(<View testID="empty" />);

expect(getByTestId('empty')).toBeEmptyElement();

Note
This matcher has been previously named toBeEmpty(), but we changed that name in order to avoid conflict with Jest Extendend matcher with the same name.

toContainElement

toContainElement(element: ReactTestInstance | null);

Check if an element contains another element as a descendant. Again, will only work for native elements.

Examples

const { queryByTestId } = render(
  <View testID="grandparent">
    <View testID="parent">
      <View testID="child" />
    </View>
    <Text testID="text-element" />
  </View>,
);

const grandparent = queryByTestId('grandparent');
const parent = queryByTestId('parent');
const child = queryByTestId('child');
const textElement = queryByTestId('text-element');

expect(grandparent).toContainElement(parent);
expect(grandparent).toContainElement(child);
expect(grandparent).toContainElement(textElement);
expect(parent).toContainElement(child);
expect(parent).not.toContainElement(grandparent);

toBeOnTheScreen

toBeOnTheScreen();

Check that the element is present in the element tree.

You can check that an already captured element has not been removed from the element tree.

Note
This matcher requires React Native Testing Library v10.1 or later, as it includes the screen object.

Note
If you're using React Native Testing Library v12 or later, you need to install Jest Native v5.4.2 or later.

Examples

render(
  <View>
    <View testID="child" />
  </View>,
);

const child = screen.getByTestId('child');
expect(child).toBeOnTheScreen();

screen.update(<View />);
expect(child).not.toBeOnTheScreen();

toHaveProp

toHaveProp(prop: string, value?: any);

Check that the element has a given prop.

You can optionally check that the attribute has a specific expected value.

Examples

const { queryByTestId } = render(
  <View>
    <Text allowFontScaling={false} testID="text">
      text
    </Text>
    <Button disabled testID="button" title="ok" />
  </View>,
);

expect(queryByTestId('button')).toHaveProp('accessible');
expect(queryByTestId('button')).not.toHaveProp('disabled');
expect(queryByTestId('button')).not.toHaveProp('title', 'ok');

toHaveTextContent

toHaveTextContent(text: string | RegExp, options?: { normalizeWhitespace: boolean });

Check if an element or its children have the supplied text.

This will perform a partial, case-sensitive match when a string match is provided. To perform a case-insensitive match, you can use a RegExp with the /i modifier.

To enforce matching the complete text content, pass a RegExp.

Examples

const { queryByTestId } = render(<Text testID="count-value">2</Text>);

expect(queryByTestId('count-value')).toHaveTextContent('2');
expect(queryByTestId('count-value')).toHaveTextContent(2);
expect(queryByTestId('count-value')).toHaveTextContent(/2/);
expect(queryByTestId('count-value')).not.toHaveTextContent('21');

toHaveStyle

toHaveStyle(style: object[] | object);

Check if an element has the supplied styles.

You can pass either an object of React Native style properties, or an array of objects with style properties. You cannot pass properties from a React Native stylesheet.

Examples

const styles = StyleSheet.create({ text: { fontSize: 16 } });

const { queryByText } = render(
  <Text
    style={[
      { color: 'black', fontWeight: '600', transform: [{ scale: 2 }, { rotate: '45deg' }] },
      styles.text,
    ]}
  >
    Hello World
  </Text>,
);

expect(getByText('Hello World')).toHaveStyle({ color: 'black' });
expect(getByText('Hello World')).toHaveStyle({ fontWeight: '600' });
expect(getByText('Hello World')).toHaveStyle({ fontSize: 16 });
expect(getByText('Hello World')).toHaveStyle([{ fontWeight: '600' }, { color: 'black' }]);
expect(getByText('Hello World')).toHaveStyle({ color: 'black', fontWeight: '600', fontSize: 16 });
expect(getByText('Hello World')).toHaveStyle({ transform: [{ scale: 2 }, { rotate: '45deg' }] });
expect(getByText('Hello World')).not.toHaveStyle({ color: 'white' });
expect(getByText('Hello World')).not.toHaveStyle({ transform: [{ scale: 2 }] });
expect(getByText('Hello World')).not.toHaveStyle({
  transform: [{ rotate: '45deg' }, { scale: 2 }],
});

toBeVisible

toBeVisible();

Check that the given element is visible to the user.

An element is visible if all the following conditions are met:

  • it does not have its style property display set to none.
  • it does not have its style property opacity set to 0.
  • it is not a Modal component or it does not have the prop visible set to false.
  • it is not hidden from accessibility as checked by isHiddenFromAccessibility function from React Native Testing Library
  • its ancestor elements are also visible.

Examples

const { getByTestId } = render(<View testID="empty-view" />);

expect(getByTestId('empty-view')).toBeVisible();
const { getByTestId } = render(<View testID="view-with-opacity" style={{ opacity: 0.2 }} />);

expect(getByTestId('view-with-opacity')).toBeVisible();
const { getByTestId } = render(<Modal testID="empty-modal" />);

expect(getByTestId('empty-modal')).toBeVisible();
const { getByTestId } = render(
  <Modal>
    <View>
      <View testID="view-within-modal" />
    </View>
  </Modal>,
);

expect(getByTestId('view-within-modal')).toBeVisible();
const { getByTestId } = render(<View testID="invisible-view" style={{ opacity: 0 }} />);

expect(getByTestId('invisible-view')).not.toBeVisible();
const { getByTestId } = render(<View testID="display-none-view" style={{ display: 'none' }} />);

expect(getByTestId('display-none-view')).not.toBeVisible();
const { getByTestId } = render(
  <View style={{ opacity: 0 }}>
    <View>
      <View testID="view-within-invisible-view" />
    </View>
  </View>,
);

expect(getByTestId('view-within-invisible-view')).not.toBeVisible();
const { getByTestId } = render(
  <View style={{ display: 'none' }}>
    <View>
      <View testID="view-within-display-none-view" />
    </View>
  </View>,
);

expect(getByTestId('view-within-display-none-view')).not.toBeVisible();
const { getByTestId } = render(
  <Modal visible={false}>
    <View>
      <View testID="view-within-not-visible-modal" />
    </View>
  </Modal>,
);

// Children elements of not visible modals are not rendered.
expect(queryByTestId('view-within-modal')).toBeNull();
const { getByTestId } = render(<Modal testID="not-visible-modal" visible={false} />);

expect(getByTestId('not-visible-modal')).not.toBeVisible();
const { getByTestId } = render(<View testID="test" accessibilityElementsHidden />);

expect(getByTestId('test')).not.toBeVisible();
const { getByTestId } = render(
  <View testID="test" importantForAccessibility="no-hide-descendants" />,
);

expect(getByTestId('test')).not.toBeVisible();

toHaveAccessibilityState

toHaveAccessibilityState(state: {
  disabled?: boolean;
  selected?: boolean;
  checked?: boolean | 'mixed';
  busy?: boolean;
  expanded?: boolean;
});

Check that the element has given accessibility state entries.

This check is based on accessibilityState prop but also takes into account the default entries which have been found by experimenting with accessibility inspector and screen readers on both iOS and Android.

Some state entries behave as if explicit false value is the same as not having given state entry, so their default value is false:

  • disabled
  • selected
  • busy

The remaining state entries behave as if explicit false value is different than not having given state entry, so their default value is undefined:

  • checked
  • expanded

This matcher is compatible with *ByRole and *ByA11State queries from React Native Testing Library.

Examples

render(<View testID="view" accessibilityState={{ expanded: true, checked: true }} />);

// Single value match
expect(screen.getByTestId('view')).toHaveAccessibilityState({ expanded: true });
expect(screen.getByTestId('view')).toHaveAccessibilityState({ checked: true });

// Can match multiple entries
expect(screen.getByTestId('view')).toHaveAccessibilityState({ expanded: true, checked: true });

Default values handling:

render(<View testID="view" />);

// Matching states where default value is `false`
expect(screen.getByTestId('view')).toHaveAccessibilityState({ disabled: false });
expect(screen.getByTestId('view')).toHaveAccessibilityState({ selected: false });
expect(screen.getByTestId('view')).toHaveAccessibilityState({ busy: false });

// Matching states where default value is `undefined`
expect(screen.getByTestId('view')).not.toHaveAccessibilityState({ checked: false });
expect(screen.getByTestId('view')).not.toHaveAccessibilityState({ expanded: false });

toHaveAccessibilityValue

toHaveAccessibilityValue(value: {
  min?: number;
  max?: number;
  now?: number;
  text?: string | RegExp;
});

Check that the element has given accessibilityValue prop entries.

This matcher is compatible with *ByRole and *ByA11Value queries from React Native Testing Library.

Examples

render(<View testID="view" accessibilityValue={{ min: 0, max: 100, now: 65 }} />);

const view = screen.getByTestId('view');

// Single value match
expect(view).toHaveAccessibilityValue({ now: 65 });
expect(view).toHaveAccessibilityValue({ max: 0 });

// Can match multiple entries
expect(view).toHaveAccessibilityValue({ min: 0, max: 100 });
expect(view).toHaveAccessibilityValue({ min: 0, max: 100, now: 65 });

// All specified entries need to match
expect(view).not.toHaveAccessibilityValue({ now: 45 });
expect(view).not.toHaveAccessibilityValue({ min: 20, max: 100, now: 65 });
render(<View testID="view" accessibilityValue={{ text: 'Almost full' }} />);

const view = screen.getByTestId('view');
expect(view).toHaveAccessibilityValue({ text: 'Almost full' });
expect(view).toHaveAccessibilityValue({ text: /full/ });

Inspiration

This library was made to be a companion for React Native Testing Library.

It was inspired by jest-dom, the companion library for DTL. We emulated as many of those helpers as we could while keeping in mind the guiding principles.

Other solutions

None known, you can add the first!

Contributors

Thanks goes to these wonderful people (emoji key):


Brandon Carroll

💻 📖 🚇 ⚠️

Santi

💻

Marnus Weststrate

💻

Matthieu Harlé

💻

Alvaro Catalina

💻

ilker Yılmaz

📖

Donovan Hiland

💻 ⚠️

This project follows the all-contributors specification. Contributions of any kind welcome!

jest-native's People

Contributors

allcontributors[bot] avatar bcarroll22 avatar belgamo avatar brunohkbx avatar dependabot[bot] avatar felippepuhle avatar grohden avatar hugochollet avatar ilkeryilmaz avatar imgbot[bot] avatar jeremyshearer avatar jgornick avatar joaogabriel55 avatar kaibarnes avatar marnusw avatar mateusbw avatar mdjastrzebski avatar michaeldeboey avatar mironiasty avatar ne3l avatar nickmccurdy avatar philipbulley avatar r0mankon avatar ramos-ph avatar ronaldoaraujo avatar santima10 avatar sbalay avatar shywim avatar thymikee avatar yonatan-altaraz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

jest-native's Issues

can't assert that an element is empty

  • react-native or expo: react-native
  • @testing-library/react-native version: 5.0.1
  • jest-preset: @testing-library/react-native
  • react-native version: 0.61.4
  • node version: 12.4.0

Relevant code or config:

const { queryByText } = render(<Root />)

expect(queryByText('Not There')).toBeEmpty();

What you did:

Tried to assert that an element is not renderered

What happened:

 TypeError: Cannot read property 'type' of null

on this line:
expect(queryByText('Not There')).toBeEmpty();

Reproduction:

Do a queryByText of an element that won't be rendered

Problem description:

Tried to assert that an element is not renderered

Suggested solution:

Can you help us fix this issue by submitting a pull request?

toBeEmpty is incorrectly returning false when children's prop on element is false

The toBeEmpty method is incorrectly returning false when children's prop on the queried element is false. The example below is for a conditionally rendered child.

This works as expected (props => children => undefined)

     const { getByTestId } = render(<View testID="empty"></View>);

     expect(getByTestId('empty')).toBeEmpty();

but in this example the toBeEmpty method incorrectly returns false... (props => children => false)

      const conditional = false
      const { getByTestId } = render(<View testID="notEmpty">{ conditional && <View testID="empty"/> }</View>);

      expect(getByTestId('notEmpty')).toBeEmpty();

refactor: migrate code to TypeScript

Describe the feature you'd like:

Current code is written in JavaScript without any from of strong typing. We provide a TypeScript types file.

Idea is to migrate the whole code base to use TS.

Suggested implementation:

Migrate all code files to typescript.

Describe alternatives you've considered:

  • Stay as is, but we loss benefits of static type checking in our code.

Teachability, Documentation, Adoption, Migration Strategy:

  • Apply existing types to publicly exported functions
  • Add missing types
  • Remove type declaration file

toBeEmptyElement isn't working as expected

  • react-native or expo: vanilla RN
  • @testing-library/react-native version: 11.5.0
  • @testing-library/jest-native version: 5.3.1
  • jest-preset: 'react-native'
  • react-native version: 70.6
  • node version: v16.15.1

Relevant code or config:

The relevant code appears to be here: https://github.com/testing-library/jest-native/blob/main/src/to-be-empty-element.ts#L9

Here's a minimal repro:

import { render } from '@testing-library/react-native';
import { Text } from 'react-native';

function Test() {
  return <Text>hello</Text>
}

test('renders correctly', () => {
  const { container } = render(<Test />);
  expect(container).toBeEmptyElement()  // this should fail, but passes
});

What you did:

First, I tried to use toBeEmptyElement in a test to assert that null was returned from a component. Noticed it passed (yay!), then I tried a negative test to make sure that the test failed if non-null was returned. The test still passed, when a failure was expected 🤔.

What happened:

The referenced test/repro code is passing, when a failure is expected.

Reproduction:

import { render } from '@testing-library/react-native';
import { Text } from 'react-native';

function Test() {
  return <Text>hello</Text>
}

test('renders correctly', () => {
  const { container } = render(<Test />);
  expect(container).toBeEmptyElement() // this should fail, but passes
});

Problem description:

The matcher toBeEmptyElement doesn't appear to work as suggested in the docs/as expected.

Suggested solution:

I think the pass condition in toBeEmptyElement should be element?.children instead of element?.props?.children?
Relevant code: https://github.com/testing-library/jest-native/blob/main/src/to-be-empty-element.ts#L9

Can you help us fix this issue by submitting a pull request?

I believe so - I can try to find some time.

ReferenceError: expect is not defined

When I add import '@testing-library/jest-native/extend-expect'; inside my setup.js which is referenced in setupFiles inside my jest-config.json, I get this error on every test:

ReferenceError: expect is not defined

When I reference it in setupFilesAfterEnv instead, it's all working fine.

I'd be happy to push a PR to add that gotcha in the README if the maintainers thing it makes sense.

  • react-native: 0.63.2
  • @testing-library/react-native: 7.0.2
  • jest: 26.5.2
  • node version: 10.16.3

Relevant code or config:

{
  "preset": "react-native",
  "globals": {
    "__TEST__": true,
    "window": {}
  },
  "rootDir": "../",
  "setupFiles": [
    "./jest/setup.js",
    "./node_modules/react-native-gesture-handler/jestSetup.js"
  ],
  "setupFilesAfterEnv": [
    "./jest/setupAfterEnv.js"
  ],
...
}

toHaveAccessibilityValue always truthy

  • react-native
  • @testing-library/react-native version: 11.5.0
  • jest-preset: "react-native"
  • react-native version: 0.66.5
  • node version: 16.18.0

Relevant code or config:

render(<View testID="view" accessibilityState={{ text: 'Almost full', disabled: true }} />);

const view = screen.getByTestId('view');


expect(view).toHaveAccessibilityState({ text: 'Almost full', disabled: true }); // passes as expected
expect(view).toHaveAccessibilityState({ text: 'Almost full', disabled: true }); // fails as expected

expect(view).toHaveAccessibilityValue({ text: "Almost full" }); // passes as expected
expect(view).toHaveAccessibilityValue({ text: "Whatever this is wrong" }); // passes but it shouldn't pass!

What you did:

Was trying to make some assertions on a single a11y value on a test (in this project https://github.com/artsy/eigen) and noticed the behavior that I mention on the Relevant code or config part.

What happened:

The first assertion was passing as expected

expect(view).toHaveAccessibilityValue({ text: "Almost full" }); // passes as expected

but then I was like, lets make the test fail to make sure it works properly

expect(view).toHaveAccessibilityValue({ text: "Whatever this is wrong" }); // passes but it shouldn't pass!

and noticed the above.

Reproduction:

I think that it can be reproduced really easily in any project by copying the Relevant code part

Problem description:

toHaveAccessibilityValue should make the test fail if no single match is found

Suggested solution:

not sure yet but will dive deeper

Can you help us fix this issue by submitting a pull request?

Would love to help fixing this

Extending expect in typescript project

Problem description:

Thanks for maintaining this great library! I'm super excited to have found it and to start using it to more easily test react native components.

I'm trying to add this to a typescript RN project, but I'm having trouble getting this to properly extend expect. I've tried following the instructions in react-native-testing-library and here, but in both cases, typescript fails to recognize the new extensions to expect

Notes:

I see that #39 should have fixed this issue, but I'm definitely still experiencing it. I'm happy to try out a few more things or provide additional details, but I'm not sure how to proceed testing this out right now.

Missing (dist) index.js which exports all matchers for library usage

Relevant code or config:

const jestNativeMatchers = require('@testing-library/jest-native')

What you did:

Upgrade @testing-library/jest-native from 4.0.2 to 5.3.0

What happened:

Cannot find module '@testing-library/jest-native ...

Reproduction:

Try to import all or individual matchers using the code example in the README.md.

Problem description:

After inspecting the package, the main entry field in package.json points to a dist/index.js, which doesn't exist.

Suggested solution:

Re-add the barrel file (dist/index.js) to export the matchers. You can automate this part of the build too using barrelsby.

Can you help us fix this issue by submitting a pull request?

Yes, I could help submit a PR. I wanted to log the issue first to see if this is intended 😄

ramda dependency suffers from security vulnerability

Current version of ramda referenced in package.json has a security vulnerability CWE-915

Problem description:

Suggested solution:

The problem has been fixed in ramda 0.27.1. We should upgrade it to the latest compatible version.

Can you help us fix this issue by submitting a pull request?

I would love to submit a PR with a fix, but currently I'm blocked on tests failing in main branch. Once that issue has been resolved I will submit the fix

toBeVisible failing when used on Pressable with style function

  • react-native or expo: react-native
  • @testing-library/react-native version: 5.3.0
  • jest-preset: jest-expo
  • react-native version: 0.68.5
  • node version: 16.16.0

What happened:

When using .toBeVisible on a Pressable using a function for the style prop we get the following error

TypeError: Cannot destructure property 'display' of 'react_native_1.StyleSheet.flatten(...)' as it is undefined.

at isStyleVisible (node_modules/@testing-library/jest-native/dist/to-be-visible.js:9:13)

Using a function in the style prop is used for checking whether the component is currently pressed, so I think it needs to be supported.

Can you help us fix this issue by submitting a pull request?

I can make a fix for this myself.

ToBeEmpty assertion in jest-native is also used in jest-extended

Describe the feature you'd like:

Jest-Extended has an assertion named the same as jest-native's one:

-> https://github.com/jest-community/jest-extended#tobeempty
-> https://github.com/testing-library/jest-native#tobeempty

When both libs are used in the same project, the version of jest-extended overwrites the one from jest-native.

@testing-library/jest-dom has had the same problem testing-library/jest-dom#216 and they renamed their matcher to toBeEmptyDOMElement .

Suggested implementation:

I wished we could have the same matcher on both platforms, but toBeEmptyDOMElement doesn't make sense on native, so I'd suggest something like toBeEmptyElement, or toBeEmptyNode.

Teachability, Documentation, Adoption, Migration Strategy:

We should do like @testing-library/jest-dom, i.e. add the new matcher and tag the current one as deprecated.

`toHaveTextContent` skips intermediate levels in deep-nested text

  • react-native or expo: Expo
  • @testing-library/react-native version: 4.0.1
  • jest-preset: 'react-native'
  • react-native version: 0.63.2
  • node version: v16.1.0

Relevant code or config:

test('triple-nested text by text', () => {
  const { getByText } = render(
    <Text>A1 <Text>B1 <Text>C1 <Text>D </Text>C2 </Text>B2 </Text>A2</Text>
  )
  const text = getByText('A1 B1 C1 D C2 B2 A2')
  expect(text).toHaveTextContent('A1 B1 C1 D C2 B2 A2')
  // getByText works
  // toHaveTextContent fails, expects "A1 D A2" 

})

test('triple-nested text by role', () => {
  const { getByRole } = render(
    <Text accessibilityRole="header">A1 <Text>B1 <Text>C1 <Text>D </Text>C2 </Text>B2 </Text>A2</Text>
  )
  const text = getByRole('header')
  expect(text).toHaveTextContent('A1 B1 C1 D C2 B2 A2')
  // toHaveTextContent fails, expects "A1 D A2" again
})

What you did:

Tried to write Native Testing Library tests for some text nesting scenarios.

What happened:

Jest saw the outermost and innermost text but skipped everything in between.

Reproduction:

See "Relevant code or config"

Problem description:

Can't test scenarios where text is nested more than one level of text (not views).

Suggested solution:

Can you help us fix this issue by submitting a pull request?

If I have time later I'll see how this relates to #61

Call for maintainers

Is anyone interested in helping maintain this project. The primary maintainer is no longer able to maintain it.

toBeVisible ignores opacity via color property

  • react-native or expo: Expo 47
  • @testing-library/react-native version: ^12.0.0-rc.0
  • jest-preset: "jest-expo"
  • react-native version: "0.70.5"
  • node version: v14.21.2.

Relevant code or config:

import React from 'react'
import { Text } from 'react-native'
import { render, screen } from '@testing-library/react-native'

test('Invisible text with property', () => {
  render(<Text style={{ opacity: 0 }}>I am invisible</Text>)

  expect(screen.getByText('I am invisible')).not.toBeVisible()
})

test('Invisible text with color', () => {
  render(<Text style={{ color: '#fff0' }}>So am I!</Text>)

  expect(screen.getByText('So am I!')).not.toBeVisible()
})

Produces test output:

 FAIL  features/cell/newFile.test.jsx (11.251 s)
  ✓ Invisible text with property (416 ms)
  ✕ Invisible text with color (415 ms)

  ● Invisible text with color

    expect(element).not.toBeVisible()

    Received element is visible:
      <Text
        children="So am I!"
        style={
          {
            "color": "#fff0",
          }
        }
      />

      12 |   render(<Text style={{ color: '#fff0' }}>So am I!</Text>)
      13 |
    > 14 |   expect(screen.getByText('So am I!')).not.toBeVisible()
         |                                            ^
      15 | })
      16 |

      at Object.<anonymous> (features/cell/newFile.test.jsx:14:44)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        11.874 s

What you did:

I was converting my old Enzyme tests to use React Native Testing Library and trying to take advantage of the Jest Native idiomatic assertions.

What happened:

My test failed because I was using color: '#fff0' or color: '#ffff' to toggle visibility of some text in my React Native app. According to expect(...).not.toBeVisible(), it was visible, but this ignores the alpha element of the color hexadecimal code.

Reproduction:

See above.

Problem description:

It's not a major issue but it means I have to change my production code to fix the test when I think the test should just work as is. Perhaps you won't think it's important but I didn't see it reported in the Issues tab, so I'm reporting it.

Suggested solution:

Add a further check function in to-be-visible.ts which checks color for the optional opacity character(s) in hex string and also in rgba(x,x,x,x).

Can you help us fix this issue by submitting a pull request?

Yes, probably, though I'm not super familiar with the various versions of this that exist (probably rgba, 6 digit hashes, etc). The relevant information in React Native appears to be here.

Property 'toHaveStyle' does not exist on type 'JestMatchers<any>'

I've just installed jest-native and when I try to use toHaveStyle() I got this error:

Screen Shot 2021-12-23 at 4 46 12 p m

This is the complete example:

const commonStyles: TextStyle = {
  fontFamily: 'ProximaNova',
  fontSize: 14,
  lineHeight: 20,
  color: getColor('gray-100'),
}

describe('TextInfo', () => {
  it('should render the given text with default styles', () => {
    const { getByText } = render(<TextInfo>{sampleText}</TextInfo>)
    expect(getByText(sampleText)).toHaveStyle(commonStyles)
    expect(getByText(sampleText)).toBeTruthy()
  })

  it('should render the given text with custom styles', () => {
    const { getByText } = render(
      <TextInfo style={{ marginBottom: 8 }}>{sampleText}</TextInfo>,
    )
    expect(getByText(sampleText)).toHaveStyle({
      ...commonStyles,
      marginBottom: 8,
    })
    expect(getByText(sampleText)).toBeTruthy()
  })
})

How can I get rid off this error?

toHaveStyle breaks if style is a nested array

  • react-native or expo: react-native
  • @testing-library/react-native version: 11.0.0
  • jest-preset: react-native
  • react-native version: 0.68.2
  • node version: 16

Problem description:

Problem was introduced on v4.0.11, after removing ramda.

Suggested solution:

Keep going deep when merging styles, or maybe using StyleSheet.flatten

Reproduction:

describe('toHaveStyle tests', () => {
  it('success', () => {
    const { getByText } = render(
      <Text style={[{ color: 'blue' }, [{ color: 'red' }]]}>Hey</Text>
    )

    expect(getByText('Hey')).toHaveStyle({
      color: 'red',
    })
  })

  it('fail', () => {
    const { getByText } = render(
      <Text style={[{ color: 'blue' }, [[{ color: 'red' }]]]}>Hey</Text>
    )

    expect(getByText('Hey')).toHaveStyle({
      color: 'red',
    })
  })
})

Can you help us fix this issue by submitting a pull request?

I can look at it during my weekends, most likely on the next one

toHaveProp does't work properly with @testing-library/react-native: 7.0.2 (latest)

  • react-native: "^0.59.6"
  • @testing-library/react-native version: "7.0.2"
  • node version: v12.12.0

Relevant code or config:

this code is coppied from jest-native -> src/to-have-prop.js:

const isAllowed = VALID_ELEMENTS.includes(element.type);

it assumes element.type is a string, but in the new testing-library version when accessing the element using getByText accessor, i get an object with type: {... , displayName: 'string', ...}, so isAllowed is false and the test passes with wrong expected value.

What you did:

test('.toHaveProp', () => {
  const { queryByTestId, getByText } = render(
    <View>
      <Text allowFontScaling={false} testID="text">
        text
      </Text>
      <Button disabled testID="button" title="ok" />
    </View>,
  );
  expect(getByText('text')).toHaveProp('allowFontScaling', 'wrongValue')

What happened:

this example test does not fail even though a wrong expected value was provided

Reproduction:

here's a branch that recreates the problem
i've made minimum changes to make it work with the new @testing-library/react-native version, also removed other tests cause it caused other failures.

Suggested solution:

check the element.type type to see if it's a string or an object.

Can you help us fix this issue by submitting a pull request?

i've opened a pr that fixes it

toBeDisabled does not equal not.toBeEnabled

  • react-native or expo: react-native
  • @testing-library/react-native version: 3.4.3
  • jest-preset: react-native
  • react-native version: 0.63.4
  • node version: v15.5.0

Relevant code or config:

it('toBeDisabled should equal not.toBeEnabled', async () => {
  const {getByTestId} = await render(
      <Pressable disabled={true}>
        <Pressable testID="subject" disabled={false} />
      </Pressable>,
  );
  const subject = getByTestId('subject');

  expect(subject).toBeDisabled();

  // This expectation fails
  expect(subject).not.toBeEnabled();
});

What you did:

Run this test.

What happened:

The second expectation fails, which I believe it should not do.

Reproduction:

I forked the template and made my changes (btw: the template is quite out of date, so I updated it to require the same versions as I run into this issue with).
The relevant file is here: https://github.com/Punksmurf/ntl-sample/blob/master/src/__tests__/App-test.js

Problem description:

As a user, I expect toBeEnabled() and toBeDisabled() to be opposites, and therefore I expect .toBeDisabled() to yield the same result as .not.toBeEnabled(). This however is not the case.

I do not know if this is actually expected behaviour; the readme states that toBeEnabled() works similarly to .not.toBeDisabled(). It should also be noted that it indeed does; it's the other way around that I think is problematic.

The cause, as far as I can see, is in to-be-disabled.js:66. This differs from line 47 in that for the toBeDisabled() the ancestors are checked and for toBeEnabled() they are not.

Suggested solution:

Changing to-be-disabled.js:66 to var isEnabled = !(isElementDisabled(element) || isAncestorDisabled(element)); seems to fix the issue, however I am not comfortable recommending this change as I have almost no understanding of the internal workings of the testing library. Given that isAncestorDisabled() loops through quite a bit more ancestors (7) than I would expect (namely just the one), this is not just the view hierarchy and there may be subtleties at play that I do not know of.

Can you help us fix this issue by submitting a pull request?

I could create a PR with the above mentioned solution, if that is indeed the fix.

.toBeDisabled() buggy with RN 0.62

  • react-native or expo: 0.62.1
  • @testing-library/react-native version: 3.1.0
  • react-native version: 0.62.1
  • node version: 12.16.1

Latest version of RN deprecated accessibilityStates in favor of accessibilityState
https://reactnative.dev/blog/2020/03/26/version-0.62#breaking-changes

Seems like now it's an object
facebook/react-native@7b35f42

I suspect we need to change it here

path(['props', 'accessibilityStates']),

It's quite weird that in my codebase everything works fine except 1 use case where I have something like this

<TouchableOpacity disabled testID="button">
  <Button disabled>

And when I check it fails, no matter if the received output from jest seems to be correct and it has the disabled prop and it's true

{
  "disabled": true,
  "testID": "button",
  "children": <Button>
}

Can you help us fix this issue by submitting a pull request?

I checked the codebase and there is an intense use of ramda which hurts my eyes and find it quite difficult to work with, but I'll try to make a PR 😄

Matcher toBeDisabled does not take into account the editable prop of TextInput

Problem / Feature Request

The matcher toBeDisabled does not take into account the editable prop of the <TextInput /> component.

render(<TextInput testId="input" editable={false}/>)
expect(screen.getByTestId("input")).toBeDisabled() // will fail

In the readme.md, it says:

Check whether or not an element is disabled from a user perspective

In my opinion when we have <TextInput editable={false}/> the element appears to be disabled from a user perspective

What do you think of adding the editable prop into the checks of the matcher toBeDisabled ?

Environment

@testing-library/react-native version: 11.3.0
jest-preset: react-expo
react-native version: 0.69.6
node version: 18.11

Broken link in README ('Usage' section)

What you did:

Clicked on link 'tests setup file' in Usage section of README:

Import @testing-library/jest-native/extend-expect once (for instance in your tests setup file) and you're good to go:

What happened:

Took me to top of the linked page.

What should have happened:

Should have taken me to specific section given by this link:
https://jestjs.io/docs/configuration#setupfilesafterenv-array

Can you help us fix this issue by submitting a pull request?

Too noobish and lazy sorry. :)

toBeDisabled does not work with styled-components

  • react-native or expo: react-native
  • @testing-library/react-native version: 3.3.0
  • jest-preset: not installed, but I'm sure this doesn't matter
  • react-native version: 0.63.2
  • node version: 10
  • styled-components version: 5.1.1

Relevant code or config:

{ 
  "dependencies": {
    "react": "16.13.1",
    "react-native": "0.63.2",
    "styled-components": "^5.1.1",
  }
}

Consider this code. It renders a button styled with styled-components.

// MyComponent.tsx
export function MyComponent() {
  return (<StyledButton testID="testButton" disabled>
        <Text>Hello</Text>
      </StyledButton>);
}

const StyledButton = styled.TouchableOpacity``;

This test checks whether the button is disabled.

// MyComponent.test.tsx
it("disables the button", () => {
    const renderer = render(
      <MyComponent />,
    );

    expect(renderer.getByTestId("testButton")).toHaveProp("disabled", true); // passes
    expect(renderer.getByTestId("testButton")).toBeDisabled(); // fails
  });

What you did:

I wrote the test above

What happened:

The test fails with this message:

expect(element).toBeDisabled()

    Received element is not disabled:
      Object {
      "props": Object {
        "children": <Text>
          Hello
        </Text>,
        "disabled": true,
        "testID": "testButton",
      },
    }

Reproduction:

I might do that later and edit this bug report, I think it's reproducable with the information above

Problem description:

The test fails because toBeDisabled() checks for the name of the component to be any of the known RN types. However styled-component wraps those components and doesn't retain the name. In dist/utils.js the function getType() checks for the name, and the component name returns Styled(Component) for type.displayName. So, it does not match the string TouchableOpacity and the matcher returns false.

Suggested solution:

IDK, the two alternatives that I can think of now are a) not checking for the name at all and b) unwrapping that component somehow if we 'detect' it's a styled-component. Not sure if that's possible though.

Can you help us fix this issue by submitting a pull request?

I guess, depends on what we could do to solve this

Bump version of jest-diff

Describe the feature you'd like:

The current version of jest diff - 24.0.0, relies on [email protected], which it now seems to be defaulting to for me, and I've not had any luck resolving my package.json to a later version.

Suggested implementation:

Bump jest-diff, at least to 27.x

Describe alternatives you've considered:

n/a

Teachability, Documentation, Adoption, Migration Strategy:

Property 'toBeOnTheScreen' does not exist on type 'JestMatchers<ReactTestInstance>' (TS project)

  • react-native or expo: RN
  • @testing-library/react-native version: ^11.4.0
  • jest-preset: "react-native"
  • react-native version: 0.70.6
  • node version: 16

Relevant code or config:

const menuTitle = screen.getByText("My wonderful title");
expect(menuTitle).toBeOnTheScreen(); // tsc error

What you did:

Try to use custom matcher in a TS project that check types with tsc.

What happened:

Typescript check error.

Reproduction:

const menuTitle = screen.getByText("My wonderful title");
expect(menuTitle).toBeOnTheScreen(); // tsc error

Problem description:

Custom matcher of jest-native are not exposed as TS types. So a TS project have issue when build with TS compiler (tsc):
Ex:
Property 'toBeOnTheScreen' does not exist on type 'JestMatchers<ReactTestInstance>' (TS project)

Suggested solution:

expose types in package.json

Consider removing peer dependencies

Describe the feature you'd like:

Currently, jest-native defines a set of peer dependencies such as react, react-native and react-test-renderer.

I noticed that it uses * as the version range, which is not really good as it will accept any upcoming versions that might brake the usage. However, after looking at the code, I think there's no reason to define those as peer dependencies.

As a comparison, jest-dom package doesn't specify any peer dependency.

Suggested implementation:

Remove the peer dependencies.

Describe alternatives you've considered:

N/A

Teachability, Documentation, Adoption, Migration Strategy:

Nothing to be done as this won't be a breaking change and no migration is needed.

toHaveStyle does not find all styles

Describe the feature you'd like:

I have the same (similar) issue. There is a component:
<MaterialIcons testID="iconID" style={[styles.icon, {backgroundColor: '#ff0000'}]} />

the styles.js looks like this:
icon: { color: Colors.paleWhite, },

When I create a snapshot, it gives me this:
... <Text allowFontScaling={false} style={ Array [ Object { "color": undefined, "fontSize": 22, }, Array [ Object { "color": "#EDEDED", "margin": 15, }, Object { "backgroundColor": "#7692DD", }, ], Object { "fontFamily": "Material Icons", "fontStyle": "normal", "fontWeight": "normal", }, Object {}, ] } testID="iconID" >

But when I try to match against a style expect(sut.queryByTestId('iconID')).toHaveStyle([ {fontFamily: 'Material Icons', backgroundColor: '#ff0000'}, ]);

It can't find backgroundColor (which is one more level in). It does find fontFamily.

Suggested implementation:

Search for styles in the inner arrays also

Describe alternatives you've considered:

Teachability, Documentation, Adoption, Migration Strategy:

Unit tests fail locally using `main` branch

  • react-native or expo: react-native
  • @testing-library/react-native version: 6.0.0
  • jest-preset: N/A
  • react-native version: 0.63.2
  • node version: v14.18.3

Relevant code or config:

N/A

What you did:

Clone the repository locally and run the command npm run test or npm test.

What happened:

The command fails with the following errors:

 FAIL  src/__tests__/to-contain-element.js
  ● Test suite failed to run

    TypeError: _interopRequireDefault is not a function

      at Object.<anonymous> (node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:3:17)

 FAIL  src/__tests__/to-be-disabled.js
  ● Test suite failed to run

    TypeError: _interopRequireDefault is not a function

      at Object.<anonymous> (node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:3:17)

 FAIL  src/__tests__/to-have-prop.js
  ● Test suite failed to run

    TypeError: _interopRequireDefault is not a function

      at Object.<anonymous> (node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:3:17)

 FAIL  src/__tests__/to-be-empty.js (6.679 s)
  ● Console

    console.error
      The above error occurred in the <AppContainer> component:
          in AppContainer (at src/index.js:26)

      Consider adding an error boundary to your tree to customize error handling behavior.
      Visit https://fb.me/react-error-boundaries to learn more about error boundaries.

      at console.Object.<anonymous>.console.error (node_modules/react-native/Libraries/LogBox/LogBox.js:33:14)

  ● .toBeEmpty

    TypeError: _interopRequireDefault is not a function

      at Object.<anonymous> (node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:3:17)

 FAIL  src/__tests__/to-have-style.js (7.117 s)
  ● .toHaveStyle › handles positive test cases

    TypeError: _interopRequireDefault is not a function

      at Object.<anonymous> (node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:3:17)

 FAIL  src/__tests__/to-have-text-content.js (7.122 s)
  ● .toHaveTextContent › handles positive test cases

    TypeError: _interopRequireDefault is not a function

      at Object.<anonymous> (node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:3:17)

Reproduction:

It's not really required to create a specific repository for reproducing the issue, as it can be reproduced with the current state of the main branch (0dbda71).

Problem description:

It's not expected that tests fail when using the main branch.

Suggested solution:

I couldn't come up with a solution so far, further investigations should be performed in order to identify the cause of the error. I'd appreciate it if someone else could take a look at this or provide some guidance/clues.

Can you help us fix this issue by submitting a pull request?

TBD

queryByLabelText not working for custom components

I am trying to figure out why this test works:

test('test 1', () => {
  const { queryByLabelText, debug } = render(
    <View accessibilityLabel={'parent'}>
      <Text>One</Text>
      <View>
        <Text>Two</Text>
        <Text>Three</Text>
      </View>
    </View>
  );

  debug();
  expect(queryByLabelText('parent')).toHaveTextContent('OneTwoThree');
});

but after moving part of hierarchy to separate component it stopped to pass:

test('test 2', () => {
  const { queryByLabelText, debug } = render(
    <View accessibilityLabel={'parent'}>
      <Text>One</Text>
      <TestComponent />
    </View>
  );

  debug();
  expect(queryByLabelText('parent')).toHaveTextContent('OneTwoThree');
});

const TestComponent = () => {
  return (
    <View>
      <Text>Two</Text>
      <Text>Three</Text>
    </View>
  );
};

Error for 2nd test:

  Expected element to have text content:
    OneTwoThree
  Received:
    One

Both tests have the same snapshot printed by debug method:

    <View
      accessibilityLabel="parent"
    >
      <Text>
        One
      </Text>
      <View>
        <Text>
          Two
        </Text>
        <Text>
          Three
        </Text>
      </View>
    </View>

Is it intentional behavior?

Tested with:

  • @testing-library/jest-native: 4.0.1
  • @testing-library/react-native: 8.0.0-rc.1

`toHaveProp` not working on Button

  • react-native or expo: react-native (ver. 4.8.0)
  • @testing-library/react-native version: 5.0.3
  • jest-preset: react-native
  • react-native version: 0.62.2
  • node version: v12.16.3

Relevant code or config:

import React from 'react';
import {View, Text, Button} from 'react-native';
import {render} from '@testing-library/react-native';
import '@testing-library/jest-native/extend-expect';

test('toHaveProp works correctly', () => {
  const {queryByTestId} = render(
    <View>
      <Text allowFontScaling={false} testID="text">
        text
      </Text>
      <Button disabled testID="button" title="ok" />
    </View>,
  );

  expect(queryByTestId('button')).toHaveProp('accessibilityStates', [
    'disabled',
  ]);
  expect(queryByTestId('button')).toHaveProp('accessible');
  expect(queryByTestId('button')).not.toHaveProp('disabled');
  expect(queryByTestId('button')).not.toHaveProp('title', 'ok');
});

What you did:

Running toHaveProp sample code for jest-native website.

What happened:

Test fails with following error:

 FAIL  __tests__/jestNative.test.tsx
  ● toHaveProp works correctly

    expect(element).toHaveProp("accessibilityStates", ["disabled"]) // element.getAttribute("accessibilityStates") === ["disabled"]

    Expected the element to have prop:
      accessibilityStates=["disabled"]
    Received:
      null

      14 |   );
      15 | 
    > 16 |   expect(queryByTestId('button')).toHaveProp('accessibilityStates', [
         |                                   ^
      17 |     'disabled',
      18 |   ]);
      19 |   expect(queryByTestId('button')).toHaveProp('accessible');

      at Object.<anonymous> (__tests__/jestNative.test.tsx:16:35)

Test Suites: 1 failed, 1 passed, 2 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        2.456s, estimated 5s

Reproduction:

I've setup a repro repository on github: https://github.com/mdjastrzebski/repro-jest-native-to-have-prop

Basically it's fresh React Native CLI projects, with current version of @testing-library/react-native and @testing-library/jest-native. I have also seen the same problem when using react-native-testing-library instead of @testing-library/react-native.

Problem description:

toHaveProp does not seem to recognize some props on the Button elements. Sample code from jest-native docs fails.

Additional question: why is disabled and title from sample docs supposed to not be recognized by toHaveProp? Is it some issue related to Button or toHaveProp?

Suggested solution:

Fix 'toHaveProp' to work correctly on docs sample code OR fix the docs.
Document and explain non-trival behavior when checking Button props.

Can you help us fix this issue by submitting a pull request?

Not really, as I do not know what should be the expected behavior.

Correct setup in react-native typescript project

Hello,

There are any correct setup to use with TS?

I try to import import '@testing-library/jest-native/extend-expect' in File.test.tsx, but it falls.

Autocomplete and functions doesnt works.

Versions:

   "@testing-library/jest-native": "^3.1.0",
    "@testing-library/react-native": "^5.0.3",

Jest config:

 "jest": {
    "preset": "jest-expo",
    "transformIgnorePatterns": [
      "node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base)"
    ],
    "setupFilesAfterEnv": [
      "./src/setupTest.js"
    ]
  }

toHaveTextContent doesn't work properly when a custom component doesn't use children

  • react-native version: 0.64.2
  • @testing-library/react-native version: 7.2.0
  • jest-preset: 'react-native'
  • node version: v15.13.0
  • @testing-library/jest-native version: 4.0.1

Relevant code or config:

See reproduction section.

What you did:

I've been testing my application, but the text match doesn't work properly, I've come across 2 bugs, one which is covered by #59 and another that is described in this issue.

What happened:

The toHaveTextContent doesn't validate properly all the text content of the given element.

Screen Shot 2021-06-18 at 19 03 51

Reproduction:

import { render, act } from '_test_utils/unit-render';
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';

const HeyIDontHaveChildren = ({ text }) => {
  return (
    <TouchableOpacity>
      <Text>{text}</Text>
    </TouchableOpacity>
  );
};

const Foo = () => {
  const version = '2.16.0 (v2)';
  return (
    <View testID="VersionViewContainer">
      <Text>{version} </Text>
      <HeyIDontHaveChildren text={'Verificar atualizações'} />
    </View>
  );
};

describe('Foo', function () {
  test('Text test', async () => {
    let root = render(<Foo />);

    await act(async () => {});

    expect(root.getByTestId('VersionViewContainer')).toHaveTextContent(
      '2.16.0 (v2) Verificar atualizações',
    );
  });
});

Problem description:

The current code of the getText:

function getText(child, currentValue = '') {
let value = currentValue;
if (!child) {
return value;
} else if (Array.isArray(child)) {
return child.reduce((acc, element) => acc + getText(path(['props', 'children'], element)), '');
} else if (typeof child === 'object') {
return getText(path(['props', 'children'], child), value);
} else {
return `${value}${child}`;
}
}

Only handles components that receive children, so, if I have a custom component that doesn't receive children but instead takes a prop and passes it down bellow to its children, the getText code will not collect properly this text..

Suggested solution:

Can you help us fix this issue by submitting a pull request?

I probably can fix this.. but I know myself and I'm lazy so it will take a while to open a PR. So here's my suggestion to fix this:

I'm unsure about corner cases and about why props.children was used in the first place.. but instead of relying on props.children, use children directly:

const getChildrenText = (element) => {
    if(!element.children) {
        return typeof element === 'string' ? element : ''
    }
    
    // since this is an example this is the code.. but I would use a imperative approach with mutability for perf instead
    return element.children.reduce((texts, child) => [
        ...texts,
        ...getChildrenText(child)
    ], [])
}

getChildrenText(root.getByTestId('VersionViewContainer')).join('') // 2.16.0 (v2) Verificar atualizações

Oh, and the ramda part can look like this:

import { pipe, join, } from 'ramda' // (I would also recommend using babel-transform-imports to transform ramda imports)

const collectText = pipe(
  getChildrenText,
  join(''),
  normalize
)

const toHaveTextContent = (element, checkWith) => {
    const textContent = collectText(element)
    ....
}

Asserting a style of a parent element - There is a better way of doing this?

Hi,

I have this structure
Captura de Tela 2021-09-29 às 10 53 50

I'm able to find my icon and validate the opacity by doing it like this:
const rightIcon = getByTestId('SvgPlusIcon');

expect(rightIcon.parent?.parent?.parent?.parent).toHaveStyle({opacity: pfTheme.opacity.light});

I've looked everywhere, and couldn't find a better way of doing this instead of:
rightIcon.parent?.parent?.parent?.parent

Anyone knows how to get to the parent element in a more elegant way?

Sorry about my English, not a native speaker...

TypeScript fails to find extended expect methods

  • react-native or expo: 0.59.2
  • @testing-library/react-native version: 4.0.2
  • @testing-library/jest-native version: 3.0.1
  • jest-preset: "@testing-library/react-native"
  • react-native version: 0.59.2
  • typescript version: 3.1.6
  • node version: 10.13.0

Relevant code or config:

import * as React from "react";
import { Text } from "react-native";
import { render } from "@testing-library/react-native";

function Example() {
  return (
    <Text testID="text">2</Text>
  );
}

it("works without TypeScript errors", () => {
  const { getByTestId } = render(<Example />);

  expect(getByTestId("text")).toHaveTextContent("2");
});

What you did:

Installed jest-native within a project using TypeScript.

What happened:

I get a TypeScript error when using any of the custom matchers from the library, e.g:

Screenshot 2019-06-11 at 16 12 35

Error:(14, 31) TS2339: Property 'toHaveTextContent' does not exist on type 'Matchers<Pick<ReactTestInstance, "type" | "props" | "parent" | "children" | "find" | "findAll">>'.

Reproduction:

See code above.

Problem description:

Without the correct typings, it's not possible to use the additional assertions from the library within a TypeScript project.

Suggested solution:

Since Jest exposes expect globally, it appears we need to merge the matchers in the global namespace, meaning extend-expect.d.ts should look like this:

import { ReactTestInstance } from 'react-test-renderer';

declare global {
  namespace jest {
    interface Matchers<R> {
      toBeDisabled(): R;
      toContainElement(element: ReactTestInstance | null): R;
      toBeEmpty(): R;
      toHaveProp(attr: string, value?: any): R;
      toHaveTextContent(text: string | RegExp, options?: { normalizeWhitespace: boolean }): R;
      toBeEnabled(): R;
      toHaveStyle(style: object[] | object): R;
    }
  }
}

Peer dependency error after upgrading React to 18.1.0

  • react-native or expo: expo
  • @testing-library/react-native version: ^11.3.0
  • jest-preset: N/A
  • react-native version: ~0.70.6
  • node version: 16.15

What you did:

I just upgraded Expo to SDK 47, and I experienced a peer dependency issue on React after running npm i

What happened:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR!   react@"18.1.0" from the root project
npm ERR!   peer react@">=16.0.0" from @testing-library/[email protected]
npm ERR!   node_modules/@testing-library/jest-native
npm ERR!     dev @testing-library/jest-native@"^5.4.0" from the root project
npm ERR!   1 more (react-native)

Suggested solution:

Not sure how peer dependencies work, but is it possible that >= 16.0.0 does not match my new react version? It went from 18.0.0 to 18.1.0

Can you help us fix this issue by submitting a pull request?

I would love to help! But I need an opinion if the reason is the one suggested in the potential solution

Current project support status

I've noticed @testing-library/jest-native has been deprecated. Should this package also be deprecated, or is it actively used elsewhere?

refactor: remove Ramda dependency

Describe the feature you'd like:

Remove Ramda dependency and replace with plain JS method where possible. Ramda has affected performance of Jest tests due to badly implemented treeshaking, and attempt #82 to optimise it using custom imports have caused issues for some users.

Suggested implementation:

Replace Ramda methods like includes with their native modern JS counterparts.

Describe alternatives you've considered:

Use other utility library with better import performance, maybe Rambda (note "b" in the name)

Teachability, Documentation, Adoption, Migration Strategy:

This should be transparent to the users.

toHaveStyle support for styled-components

Since many projects are using styled-components for styling their react-native components, it would be nice if toHaveStyle would support it instead of just supporting the style property.

toHaveStyle doesn't working with nested objects/arrays

  • react-native or expo: react-native
  • @testing-library/react-native version:

├─ @testing-library/[email protected]
├─ @testing-library/[email protected]

  • jest-preset: react-native
  • react-native version: 0.63.1
  • node version: 14.2.0

Relevant code or config:

expect(getByTestId('imgComponent')).toHaveStyle({
    opacity: 1,
    transform: [
        {
            translateY: -10,
        },
    ],
})

My jest.config.js:

module.exports = {
  preset: 'react-native',
  testEnvironment: 'node',
  moduleFileExtensions: ['ts', 'tsx', 'js'],
  moduleNameMapper: {
    '^@components/(.*)$': '<rootDir>/src/components/$1',
  },
  transform: {
    '^.+\\.(js)$': '<rootDir>/node_modules/babel-jest',
    '\\.(ts|tsx)$': 'babel-jest',
  },
  testMatch: ['**/?(*.)+(test).ts?(x)'],
  testPathIgnorePatterns: ['\\.snap$', '<rootDir>/node_modules/'],
  cacheDirectory: '.jest/cache',
  setupFilesAfterEnv: [
    '@testing-library/react-native/cleanup-after-each',
    './__tests__/setupTests.ts',
  ],
  collectCoverage: false,
  coverageDirectory: '__tests__/coverage',
  collectCoverageFrom: ['src/**', '!src/interfaces/**'],
};

What you did:

Testing with toHaveStyle only works when the expected style doesn't has a nested object. For example:

// works
expect(getByTestId('imgComponent')).toHaveStyle({
    opacity: 1
});

// doesn't works
expect(getByTestId('imgComponent')).toHaveStyle({
    opacity: 1,
    transform: [
        {
            translateY: -10,
        },
    ],
})

What happened:

image

image

Problem description:

Suggested solution:

Can you help us fix this issue by submitting a pull request?

Yes

toHaveStyle with react-native-testing-library

Given the clear examples given on toHaveStyle, I am thinking the component is not supported. Basically, my custom component outputs Icon (react-native-vector-icons) based on some props. It takes one color and runs some logic to chose the background color. I prefer to test the style that is applied on the component now, which according to react-native-vector-icons is the same as Text component:

       const IconComponent =(props) => {
       const backgroundColor = setColor(props.color);
       return (<Icon testID="icon" name={props.name} color={props.color} backgroundColor={backgroundColor}/>
        }

test:

   import { render } from 'react-native-testing-library';
    const wrapper = render(
      <IconComponent  name="search" color="#00f" />
    );
    const element = wrapper.getByTestId('icon');

    expect(element).toHaveStyle({
      color: '#00f'
    });

 but it gives the following error:

image

❓ React Testing Library Resources

❓ Testing Library Resources

ISSUES WHICH ARE QUESTIONS WILL BE CLOSED

Property 'toHaveTextContent' does not exist on type 'Matchers<void> & ...' (and any other matcher from library)

  • react-native or expo: expo
  • @testing-library/react-native version: 11.5.0
  • jest-preset: jest-expo
  • react-native version: 0.70.5
  • node version: v16.17.1
  • @testing-library/jest-native version: 5.3.3
  • jest version: 29.3.0

Relevant code or config:

expect(await screen.findByRole('alert')).toHaveTextContent(
  'Incorrect username or password'
);

What you did:

Just using any matcher from jest-native.

What happened:

Typescript complains for missed types. For example, for toHaveTextContent matcher:

Property 'toHaveTextContent' does not exist on type 'Matchers<void> & SnapshotMatchers<void, ReactTestInstance> &
Inverse<JestMatchers<void, ReactTestInstance>> & PromiseMatchers<ReactTestInstance>'.ts(2339)

image

Reproduction:

https://github.com/alexamy/react-native-testing-library-missing-matchers
or the same code in zip archive:
react-native-testing-library-missing-matchers-45392ed44fe4fa3de64723609f6a0f74227188a4.zip

Problem description:

There is no way to use custom matchers in typescript tests for obvious reason. This problem can be 'avoided' by skipping matcher typecheck with @ts-ignore or optionally skipping test typecheck altogether, but it is not really a solution.

Suggested solution:

Modify types in @testing-library/jest-native/extend-expect.d.ts to proper extend the matchers interface.

Btw, there is also import problem on line 3.

image

Matchers interface from Jest:
image

I've tried to make declare global in project with extended jest' Matchers interface, but it seems that something is missed, I didn't get any working result from my tries, this interface seems to be unchanged.

Can you help us fix this issue by submitting a pull request?

I can make a Pull Request with solution for this problem if someone can point me how to properly modify definition file.

Using toBeOnTheScreen() matcher requires @testing-library/react-native v10.1.0 or later to be added to your devDependencies

  • expo: 43.0.1
  • @testing-library/react-native version: 12.0.0
  • jest-preset:
  • react-native version: 0.68.5
  • node version: 16.17.1

Relevant code or config:

import * as React from "react";
import { render, screen } from "../../__test__/test-renderer";

import MyComponent from "./MyComponent";

describe("Test MyComponent", () => {
  it("should render correctly", () => {
    render(
      <MyComponent />,
    );

    const elementInComponent = screen.getByTestId("test-id");
    expect(elementInComponent).toBeOnTheScreen();
  });
});

What you did:

pnpm test

What happened:

Got the following error:

 Could not import `screen` object from @testing-library/react-native.

    Using toBeOnTheScreen() matcher requires @testing-library/react-native v10.1.0 or later to be added to your devDependencies.

Reproduction:

Problem description:

I'm on version 12.0.0 of @testing-library/react-native so this is an unexpected error.

Suggested solution:

  • Could it be related to pnpm dependency management ?

Can you help us fix this issue by submitting a pull request?

toBeOnTheScreen() not Working With React-Native

  • react-native or expo:
  • @testing-library/react-native version:
  • jest-preset:
  • react-native version:
  • node version:

Relevant code or config:

const your = (code) => 'here';

What you did:

What happened:

Reproduction:

Problem description:

Suggested solution:

Can you help us fix this issue by submitting a pull request?

Add a way to test Modal components

Hi,

Its very difficult to test the Modal component in RN directly at present. It would be awesome if:

  1. there is some way to directly select the modal element
  2. check if the modal "visible" prop is in place, i.e. use a matcher like "toBeVisible()"

If not 1 & 2, it would be great if we could check if components within a modal are in fact visible or not.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.