Jest+React Native Testing Library: How to test an image src?
Asked Answered
A

5

39

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')`,
); */

  });
});
Asis answered 3/3, 2020 at 14:34 Comment(0)
T
64

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!)

Theresa answered 31/12, 2020 at 20:18 Comment(6)
image.getAttribute('src')Scantling
You can also use expect(image).toHaveAttribute('src', 'the_url') (source)Theresa
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: jestjs.io/docs/webpack#handling-static-assets if you follow their recommendations you'll end up with test-file-stub for all src on imagesTillfourd
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).Giddens
@Giddens 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.Theresa
test by alt text...genius!!!Phyl
C
9

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')
Clovis answered 19/5, 2020 at 19:19 Comment(2)
I am getting getByDataTestId is not a function I think they removed it in @testing-library/react-native": "^7.1.0Deification
I think it was just renamed to getByTestId (testing-library.com/docs/queries/bytestid).Resilient
D
7

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

Deification answered 17/2, 2021 at 9:8 Comment(1)
this always passes, check sourceKoah
I
3

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();

Infinite answered 10/5, 2021 at 13:41 Comment(0)
K
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);
Kilowatthour answered 14/12, 2022 at 20:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.