@@ -1400,6 +1400,39 @@ describe('TouchEventBoundary._onTouchStart', () => {
14001400 ) ;
14011401 } ) ;
14021402
1403+ it ( 'does not extract text when element is inside a Mask ancestor' , ( ) => {
1404+ const { defaultProps } = TouchEventBoundary ;
1405+ const boundary = new TouchEventBoundary ( defaultProps ) ;
1406+ jest . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( {
1407+ name : 'MobileReplay' ,
1408+ options : { maskAllText : false } ,
1409+ } as any ) ;
1410+
1411+ const event = {
1412+ _targetInst : {
1413+ elementType : { displayName : 'TouchableOpacity' } ,
1414+ memoizedProps : { } ,
1415+ child : {
1416+ elementType : { name : 'Text' } ,
1417+ memoizedProps : { children : 'Masked content' } ,
1418+ } ,
1419+ return : {
1420+ elementType : { name : 'RNSentryReplayMask' } ,
1421+ } ,
1422+ } ,
1423+ } ;
1424+
1425+ // @ts -expect-error Calling private member
1426+ boundary . _onTouchStart ( event ) ;
1427+
1428+ expect ( addBreadcrumb ) . toHaveBeenCalledWith (
1429+ expect . objectContaining ( {
1430+ message : 'Touch event within element: TouchableOpacity' ,
1431+ data : { path : [ { name : 'TouchableOpacity' } ] } ,
1432+ } ) ,
1433+ ) ;
1434+ } ) ;
1435+
14031436 it ( 'handles string memoizedProps (raw text fiber nodes)' , ( ) => {
14041437 const { defaultProps } = TouchEventBoundary ;
14051438 const boundary = new TouchEventBoundary ( defaultProps ) ;
@@ -1429,4 +1462,215 @@ describe('TouchEventBoundary._onTouchStart', () => {
14291462 ) ;
14301463 } ) ;
14311464 } ) ;
1465+
1466+ describe ( 'sentry-label masking' , ( ) => {
1467+ it ( 'skips sentry-label when maskAllText is enabled' , ( ) => {
1468+ const { defaultProps } = TouchEventBoundary ;
1469+ const boundary = new TouchEventBoundary ( defaultProps ) ;
1470+ jest . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( {
1471+ name : 'MobileReplay' ,
1472+ options : { maskAllText : true } ,
1473+ } as any ) ;
1474+
1475+ const event = {
1476+ _targetInst : {
1477+ elementType : { displayName : 'Button' } ,
1478+ memoizedProps : {
1479+ 'sentry-label' : 'secret-label' ,
1480+ accessibilityLabel : 'Save workout' ,
1481+ } ,
1482+ } ,
1483+ } ;
1484+
1485+ // @ts -expect-error Calling private member
1486+ boundary . _onTouchStart ( event ) ;
1487+
1488+ expect ( addBreadcrumb ) . toHaveBeenCalledWith (
1489+ expect . objectContaining ( {
1490+ message : 'Touch event within element: Save workout' ,
1491+ data : { path : [ { name : 'Button' , label : 'Save workout' } ] } ,
1492+ } ) ,
1493+ ) ;
1494+ } ) ;
1495+
1496+ it ( 'skips sentry-label when maskAllText defaults to true (not set)' , ( ) => {
1497+ const { defaultProps } = TouchEventBoundary ;
1498+ const boundary = new TouchEventBoundary ( defaultProps ) ;
1499+ jest . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( {
1500+ name : 'MobileReplay' ,
1501+ options : { } ,
1502+ } as any ) ;
1503+
1504+ const event = {
1505+ _targetInst : {
1506+ elementType : { displayName : 'Button' } ,
1507+ memoizedProps : {
1508+ 'sentry-label' : 'secret-label' ,
1509+ testID : 'btn-test-id' ,
1510+ } ,
1511+ } ,
1512+ } ;
1513+
1514+ // @ts -expect-error Calling private member
1515+ boundary . _onTouchStart ( event ) ;
1516+
1517+ expect ( addBreadcrumb ) . toHaveBeenCalledWith (
1518+ expect . objectContaining ( {
1519+ message : 'Touch event within element: btn-test-id' ,
1520+ data : { path : [ { name : 'Button' , label : 'btn-test-id' } ] } ,
1521+ } ) ,
1522+ ) ;
1523+ } ) ;
1524+
1525+ it ( 'reads sentry-label when maskAllText is explicitly false' , ( ) => {
1526+ const { defaultProps } = TouchEventBoundary ;
1527+ const boundary = new TouchEventBoundary ( defaultProps ) ;
1528+ jest . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( {
1529+ name : 'MobileReplay' ,
1530+ options : { maskAllText : false } ,
1531+ } as any ) ;
1532+
1533+ const event = {
1534+ _targetInst : {
1535+ elementType : { displayName : 'Button' } ,
1536+ memoizedProps : {
1537+ 'sentry-label' : 'explicit-label' ,
1538+ accessibilityLabel : 'Save workout' ,
1539+ } ,
1540+ } ,
1541+ } ;
1542+
1543+ // @ts -expect-error Calling private member
1544+ boundary . _onTouchStart ( event ) ;
1545+
1546+ expect ( addBreadcrumb ) . toHaveBeenCalledWith (
1547+ expect . objectContaining ( {
1548+ message : 'Touch event within element: explicit-label' ,
1549+ data : { path : [ { name : 'Button' , label : 'explicit-label' } ] } ,
1550+ } ) ,
1551+ ) ;
1552+ } ) ;
1553+
1554+ it ( 'skips sentry-label when element is inside a Mask ancestor' , ( ) => {
1555+ const { defaultProps } = TouchEventBoundary ;
1556+ const boundary = new TouchEventBoundary ( defaultProps ) ;
1557+ jest . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( {
1558+ name : 'MobileReplay' ,
1559+ options : { maskAllText : false } ,
1560+ } as any ) ;
1561+
1562+ const event = {
1563+ _targetInst : {
1564+ elementType : { displayName : 'Button' } ,
1565+ memoizedProps : {
1566+ 'sentry-label' : 'masked-label' ,
1567+ accessibilityLabel : 'Fallback label' ,
1568+ } ,
1569+ return : {
1570+ elementType : { name : 'RNSentryReplayMask' } ,
1571+ } ,
1572+ } ,
1573+ } ;
1574+
1575+ // @ts -expect-error Calling private member
1576+ boundary . _onTouchStart ( event ) ;
1577+
1578+ expect ( addBreadcrumb ) . toHaveBeenCalledWith (
1579+ expect . objectContaining ( {
1580+ message : 'Touch event within element: Fallback label' ,
1581+ data : { path : [ { name : 'Button' , label : 'Fallback label' } ] } ,
1582+ } ) ,
1583+ ) ;
1584+ } ) ;
1585+
1586+ it ( 'skips sentry-label when Mask ancestor uses displayName' , ( ) => {
1587+ const { defaultProps } = TouchEventBoundary ;
1588+ const boundary = new TouchEventBoundary ( defaultProps ) ;
1589+ jest . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( {
1590+ name : 'MobileReplay' ,
1591+ options : { maskAllText : false } ,
1592+ } as any ) ;
1593+
1594+ const event = {
1595+ _targetInst : {
1596+ elementType : { displayName : 'Button' } ,
1597+ memoizedProps : {
1598+ 'sentry-label' : 'masked-label' ,
1599+ testID : 'btn-id' ,
1600+ } ,
1601+ return : {
1602+ elementType : { displayName : 'RNSentryReplayMask' } ,
1603+ } ,
1604+ } ,
1605+ } ;
1606+
1607+ // @ts -expect-error Calling private member
1608+ boundary . _onTouchStart ( event ) ;
1609+
1610+ expect ( addBreadcrumb ) . toHaveBeenCalledWith (
1611+ expect . objectContaining ( {
1612+ message : 'Touch event within element: btn-id' ,
1613+ data : { path : [ { name : 'Button' , label : 'btn-id' } , { name : 'RNSentryReplayMask' } ] } ,
1614+ } ) ,
1615+ ) ;
1616+ } ) ;
1617+
1618+ it ( 'reads sentry-label when no replay integration is present' , ( ) => {
1619+ const { defaultProps } = TouchEventBoundary ;
1620+ const boundary = new TouchEventBoundary ( defaultProps ) ;
1621+ jest . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( undefined ) ;
1622+
1623+ const event = {
1624+ _targetInst : {
1625+ elementType : { displayName : 'Button' } ,
1626+ memoizedProps : {
1627+ 'sentry-label' : 'my-label' ,
1628+ accessibilityLabel : 'Save workout' ,
1629+ } ,
1630+ } ,
1631+ } ;
1632+
1633+ // @ts -expect-error Calling private member
1634+ boundary . _onTouchStart ( event ) ;
1635+
1636+ expect ( addBreadcrumb ) . toHaveBeenCalledWith (
1637+ expect . objectContaining ( {
1638+ message : 'Touch event within element: my-label' ,
1639+ data : { path : [ { name : 'Button' , label : 'my-label' } ] } ,
1640+ } ) ,
1641+ ) ;
1642+ } ) ;
1643+
1644+ it ( 'does not check Mask ancestors when maskAllText is already enabled' , ( ) => {
1645+ const { defaultProps } = TouchEventBoundary ;
1646+ const boundary = new TouchEventBoundary ( defaultProps ) ;
1647+ jest . spyOn ( client , 'getIntegrationByName' ) . mockReturnValue ( {
1648+ name : 'MobileReplay' ,
1649+ options : { maskAllText : true } ,
1650+ } as any ) ;
1651+
1652+ const event = {
1653+ _targetInst : {
1654+ elementType : { displayName : 'Button' } ,
1655+ memoizedProps : {
1656+ 'sentry-label' : 'should-be-skipped' ,
1657+ accessibilityLabel : 'Accessible' ,
1658+ } ,
1659+ return : {
1660+ elementType : { name : 'RNSentryReplayMask' } ,
1661+ } ,
1662+ } ,
1663+ } ;
1664+
1665+ // @ts -expect-error Calling private member
1666+ boundary . _onTouchStart ( event ) ;
1667+
1668+ expect ( addBreadcrumb ) . toHaveBeenCalledWith (
1669+ expect . objectContaining ( {
1670+ message : 'Touch event within element: Accessible' ,
1671+ data : { path : [ { name : 'Button' , label : 'Accessible' } ] } ,
1672+ } ) ,
1673+ ) ;
1674+ } ) ;
1675+ } ) ;
14321676} ) ;
0 commit comments