I'm facing an issue where my test fails to find an element by text after I added the Select UI component from gluestack-ui to my React Native component.
Before adding the Select, my test works fine:
test-utils.tsx
import React from 'react'
import {render} from '@testing-library/react-native'
import { GluestackUIProvider } from "@/components/ui/gluestack-ui-provider";
import fs from 'fs';
const AllTheProviders = ({children}) => {
return (
<GluestackUIProvider>
{children}
</GluestackUIProvider>
)
}
const customRender = (ui, options?) => {
const view = render(ui, {wrapper: AllTheProviders, ...options})
const style = document.createElement('style');
style.innerHTML = fs.readFileSync('./output.css', 'utf8');
document.head.appendChild(style);
return view;
}
// re-export everything
export * from '@testing-library/react-native'
// override render method
export {customRender as render}
My component
import React, { useState } from 'react';
import { View, FlatList } from 'react-native';
import { Text } from '@/components/ui/text';
import { Input, InputField } from '@/components/ui/input';
import { Heading } from '../ui/heading';
export const JamSessionsBanner = ({ sessions }) => {
const [lieu, setLieu] = useState('');
const [date, setDate] = useState('');
const filteredSessions = sessions.filter((session) => {
const matchesLieu = lieu ? session.lieu.toLowerCase().includes(lieu.toLowerCase()) : true;
const matchesDate = date ? new Date(session.date).toDateString() === new Date(date).toDateString() : true;
return matchesLieu && matchesDate;
});
return (
<View style={{ padding: 16 }}>
<Heading>Upcoming JAM Sessions</Heading>
<FlatList
data={filteredSessions}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<View style={{ marginBottom: 16 }}>
<Text>{item.lieu}, {item.ville}</Text>
<Text>{new Date(item.date).toLocaleString()}</Text>
</View>
)}
/>
</View>
);
};
The data
export const mockSessions = [
{
id: '1',
date: '2024-10-18T19:30:00',
lieu: 'Le Café',
ville: 'Paris',
description: 'Session de jam ouverte à tous.',
musiciens: ['John Doe', 'Jane Smith'],
popularité: 100,
genre: 'reggae',
},
{
id: '2',
date: '2024-10-20T20:00:00',
lieu: 'La Ska Factory',
ville: 'Lyon',
description: 'Jam session ska.',
musiciens: ['Paul Dupont', 'Marie Lafont'],
popularité: 80,
genre: 'ska',
},
];
The jest config
module.exports = {
preset: 'react-native',
transform: {
'^.+\\.tsx?$': 'babel-jest',
},
setupFilesAfterEnv: ['<rootDir>/setupTests.ts'],
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|svg)$': 'jest-transform-stub',
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
},
testEnvironment: 'jsdom',
testPathIgnorePatterns: [
'<rootDir>/node_modules/',
'<rootDir>/e2e/',
"node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|@gluestack-ui/*|@gluestack-style/*|@legendapp/*|react-native-svg)",
],
};
The test (it pass):
import { render, screen } from '../../test-utils';
import { JamSessionsBanner } from './JamSessionsBanner';
import { mockSessions } from './jam.mock';
test('renders sessions correctly', () => {
render(<JamSessionsBanner sessions={mockSessions} />);
expect(screen.getByText(/Le Café, Paris/i)).toBeTruthy();
});
After adding the Select component, the test fails:
import React, { useState } from 'react';
import { View, FlatList } from 'react-native';
import { Text } from '@/components/ui/text';
import { Input, InputField } from '@/components/ui/input';
import { Heading } from '../ui/heading';
import {
Select,
SelectBackdrop,
SelectContent,
SelectIcon,
SelectInput,
SelectItem,
SelectPortal,
SelectTrigger
} from '@/components/ui/select';
import { ChevronDownIcon } from '../ui/icon';
export const JamSessionsBanner = ({ sessions }) => {
const [lieu, setLieu] = useState('');
const [date, setDate] = useState('');
const [selectedVille, setSelectedVille] = useState('Partout');
const villes = ['Partout', ...new Set(sessions.map(session => session.ville))];
const filteredSessions = sessions.filter((session) => {
const matchesLieu = lieu ? session.lieu.toLowerCase().includes(lieu.toLowerCase()) : true;
const matchesDate = date ? new Date(session.date).toDateString() === new Date(date).toDateString() : true;
return matchesLieu && matchesDate;
});
return (
<View style={{ padding: 16 }}>
<Heading>
Upcoming JAM Sessions
<Select selectedValue={selectedVille} onValueChange={setSelectedVille}>
<SelectTrigger variant="outline">
<SelectInput placeholder="Filter by city" />
<SelectIcon as={ChevronDownIcon} />
</SelectTrigger>
<SelectPortal>
<SelectBackdrop />
<SelectContent>
{villes.map(ville => (
<SelectItem key={ville} label={ville} value={ville} />
))}
</SelectContent>
</SelectPortal>
</Select>
</Heading>
<FlatList
data={filteredSessions}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<View style={{ marginBottom: 16 }}>
<Text>{item.lieu}, {item.ville}</Text>
<Text>{new Date(item.date).toLocaleString()}</Text>
</View>
)}
/>
</View>
);
};
The test now fails with the following error:
Unable to find an element with text: /Le Café, Paris/i
The complete console output:
FAIL components/JamSessionsBanner/JamSessionsBanner.test.tsx (5.291 s)
JamSessionsBanner
✕ renders sessions correctly (726 ms)
● JamSessionsBanner › renders sessions correctly
Unable to find an element with text: /Le Café, Paris/i
<View>
<View>
<RCTText
accessibilityRole="header"
accessible={true}
>
Upcoming JAM Sessions
<View>
<View
accessible={true}
role="button"
>
<TextInput
aria-hidden={true}
importantForAccessibility="no"
placeholder="Filter by city"
value="Partout"
/>
<RNSVGSvgView
role="img"
>
<RNSVGGroup>
<RNSVGGroup>
<RNSVGPath />
</RNSVGGroup>
</RNSVGGroup>
</RNSVGSvgView>
</View>
</View>
</RCTText>
<RCTScrollView>
<RCTScrollContentView>
<View>
<View>
<RCTText
accessible={true}
>
Le Café
,
Paris
</RCTText>
<RCTText
accessible={true}
>
18/10/2024 19:30:00
</RCTText>
</View>
</View>
<View>
<View>
<RCTText
accessible={true}
>
La Ska Factory
,
Lyon
</RCTText>
<RCTText
accessible={true}
>
20/10/2024 20:00:00
</RCTText>
</View>
</View>
</RCTScrollContentView>
</RCTScrollView>
</View>
</View>
10 | render(<JamSessionsBanner sessions={mockSessions} />);
11 | // expect(screen.getByText(/Session de jam ouverte à tous/i)).toBeTruthy();
> 12 | expect(screen.getByText(/Le Café, Paris/i)).toBeTruthy();
| ^
13 | });
14 |
15 | // test('displays empty state when no sessions are available', async () => {
at Object.getByText (components/JamSessionsBanner/JamSessionsBanner.test.tsx:12:19)
at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:17)
at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:17:9)
at _next (node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:7)
at Object.<anonymous> (node_modules/@babel/runtime/helpers/asyncToGenerator.js:14:12)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 6.34 s
What I’ve tried:
- Ensured that @testing-library/react-native is configured correctly and that the custom render includes the necessary context providers.
- I've tried to add waitFor in my test.
- The issue seems to arise only after adding the Select component. Without it, everything works as expected.
- I've checked the Select rendering and functionality in the app, and it works correctly when manually tested.
Does anyone know why @testing-library/react-native might not be able to find the text after adding Select?
If you have any insights into why adding Select could cause this issue, or if I'm missing something in the testing setup, I’d appreciate the help!