fix(packages/react-native): pass testID to the rendered Svg element (#4881)

The Icon component destructured `testID` out of its props and re-emitted it as
`data-testid`, which is a web attribute. react-native-svg only forwards `testID`
to the native view (see extractProps) and drops `data-testid`, so
`<Icon testID="my-icon" />` rendered an element that no React Native test query
or UI automation tool can find. `LucideProps` extends `SvgProps`, so the prop
type checks and the failure is silent.

v0 spread `testID` straight onto `Svg`, so this is a regression for React Native
consumers. An explicitly passed `data-testid` still reaches the element through
the remaining props, so nothing is lost for react-native-web users.

The react-native-svg test mock now maps `testID` onto `data-testid`, so the
DOM based test suite identifies elements the way React Native does. Every
existing `testID` test fails against the previous behaviour.
This commit is contained in:
Oleg Bezrukavnikov
2026-09-18 11:57:55 +02:00
committed by GitHub
parent d9f72b2525
commit 5d9cc1580a
3 changed files with 15 additions and 3 deletions
@@ -4,8 +4,9 @@ import type { LucideProps } from '../../src/createReactComponent';
export type { SvgProps } from 'react-native-svg';
const createComponent = function (name: string) {
const component = (props: LucideProps) => {
return React.createElement(name, props, props.children);
// React Native identifies elements by `testID`, the DOM equivalent is `data-testid`
const component = ({ testID, ...props }: LucideProps) => {
return React.createElement(name, { ...props, 'data-testid': testID }, props.children);
};
component.displayName = name;
+1 -1
View File
@@ -107,7 +107,7 @@ const Icon = forwardRef<SVGSVGElement, IconComponentProps>(
{
ref,
...toNativeSvgAttributes(svgAttributes),
'data-testid': testID,
testID,
...rest,
},
[
@@ -47,6 +47,17 @@ describe('Using Icon Component', () => {
expect(container.firstChild).toBeDefined();
});
it('should pass the testID to the rendered element', async () => {
const { container, getByTestId } = render(
<Icon
iconNode={airVent}
testID="air-vent-icon"
/>,
);
expect(getByTestId('air-vent-icon')).toBe(container.firstChild);
});
it('should support nonScalingStroke', async () => {
const { container } = render(
<Icon