37

In my new React Native app, I want to add some Jest tests.

One component renders a background image, which is located directly in the project in assets folder.

Now I stumbled about how to test if this image is actually taken from this path, therefore present in the component, and rendered correctly.

I tried using toHaveStyle from @testing-library/jest-native with a container, which returned the error toHaveStyleis not a function. Then I tried the same with queryByTestId, same error. When I do expect(getByTestId('background').toBeInTheDocument); then I feel this is useless, because it only checks if an element with this testId is present, but not the image source.

Please, how can I test this? Does it actually make sense to test an image source after all?

Here is my code:

1.) The component that should be tested (Background):

const Background: React.FC<Props> = () => {
  const image = require('../../../../assets/images/image.jpg');
    
  return (
    <View>
      <ImageBackground testID="background" source={image} style={styles.image}></ImageBackground>
    </View>
  );
};

2.) The test:

import React from 'react';
import {render, container} from 'react-native-testing-library';
import {toHaveStyle} from '@testing-library/jest-native';
import '@testing-library/jest-native/extend-expect';
import Background from '../Background';

describe('Background', () => {   
  test('renders Background image', () => {
    const {getByTestId} = render(<Background></Background>);
    expect(getByTestId('background').toBeInTheDocument);

/*    const container = render(<Background background={background}></Background>);
expect(container).toHaveStyle(
  `background-image: url('../../../../assets/images/image.jpg')`,
); */

/*     expect(getByTestId('background')).toHaveStyle(
  `background-image: url('../../../../assets/images/image.jpg')`,
); */

  });
});
Nathan Arthur
  • 8,287
  • 7
  • 55
  • 80
RuntimeError
  • 1,332
  • 4
  • 23
  • 41

5 Answers5

58

If you're using @testing-library/react rather than @testing-library/react-native, and you have an alt attribute on your image, you can avoid using getByDataTestId and instead use getByAltText.

it('uses correct src', async () => {
    const { getByAltText } = await render(<MyComponent />);

    const image = getByAltText('the_alt_text');

    expect(image.src).toContain('the_url');
    // or
    expect(image).toHaveAttribute('src', 'the_url')
});

Documentation.

Unfortunately, it appears that React Native Testing Library does not include getByAltText. (Thank you, @P.Lorand!)

Nathan Arthur
  • 8,287
  • 7
  • 55
  • 80
  • 2
    `image.getAttribute('src')` – Dan Apr 15 '21 at 13:48
  • 2
    You can also use `expect(image).toHaveAttribute('src', 'the_url')` ([source](https://github.com/testing-library/jest-dom#tohaveattribute)) – Nathan Arthur Apr 15 '21 at 19:43
  • I figured it's worth noting that you may never obtain the actual `src` if you have mocked out static assets as noted here via `moduleNameMapper` in the jest config: https://jestjs.io/docs/webpack#handling-static-assets if you follow their recommendations you'll end up with `test-file-stub` for all `src` on images – CTS_AE Sep 08 '21 at 19:47
  • `getByAltText` eh? Seems like a rather *novel* way of finding an image - given that alt-text is what screen readers use (and not what most users see). I was honestly expecting to find a method named `getByImage(src)` or something. Also, you can apparently use `role="img"` as well to get an image (but only works for the `img` tag or similar and not on background images like this). – cst1992 Sep 06 '22 at 09:02
  • @cst1992 Alt text is discoverable by the user on hover in the browser, so I'd argue that alt text is a lot closer to testing the user experience than querying by the src url, even disregarding the usability benefits. – Nathan Arthur Sep 06 '22 at 13:31
  • test by alt text...genius!!! – Andy Feb 28 '23 at 16:14
8

It's a little hard to say because we can't see <ImageBackground> component or what it does... But if it works like an <img> component we can do something like this.

Use a selector on the image component through its role / alt text / data-testid:

const { getByDataTestId } = render(<Background background={background}>
</Background>);

Then look for an attribute on that component:

expect(getByDataTestId('background')).toHaveAttribute('src', '../../../../assets/images/image.jpg')
Nathan Arthur
  • 8,287
  • 7
  • 55
  • 80
Devin Clark
  • 1,078
  • 11
  • 9
  • I am getting ```getByDataTestId is not a function``` I think they removed it in `@testing-library/react-native": "^7.1.0` – P.Lorand Feb 17 '21 at 08:42
6

When I used getByAltText and getByDataTestId I got is not a function error.

So what worked for me was:

const imgSource = require('../../../../assets/images/image.jpg');
const { queryByTestId } = render(<MyComponent testID='icon' source={imgSource}/>);
expect(queryByTestId('icon').props.source).toBe(imgSource);

I use @testing-library/react-native": "^7.1.0

P.Lorand
  • 1,394
  • 3
  • 17
  • 26
2

I ran into this issue today and found that if your URI is a URL and not a required file, stitching the source uri onto the testID works nicely.

export const imageID = 'image_id';
...

<Image testID={`${imageID}_${props.uri}`} ... />

Test

import {
  imageID
}, from '.';

...


const testURI = 'https://picsum.photos/200';
const { getByTestId } = render(<Component uri={testURI} />);

expect(getByTestId()).toBeTruthy();

Francis Leigh
  • 1,870
  • 10
  • 25
2

I think that you are looking for:

const uri = 'http://example.com';
const accessibilityLabel = 'Describe the image here';

const { getByA11yLabel } = render (
  <Image
    source={{ uri }}
    accessibilityLabel={accessibilityLabel}
  />
);

const imageEl = getByA11yLabel(accessibilityLabel);
expect(imageEl.props.source.uri).toBe(uri);
Sanchitos
  • 8,423
  • 6
  • 52
  • 52
Constantin
  • 3,655
  • 1
  • 14
  • 23