import { render } from '@testing-library/react-native'; import React from 'react'; import { Text, View } from 'react-native'; import { withCSQMask } from '../../../replay/csqMasking/withCSQMask'; // Mock dependencies jest.mock('@contentsquare/react-native-autocapture', () => ({ HeapIgnore: ({ children, ...props }: any) => { // eslint-disable-next-line @typescript-eslint/no-var-requires const React = require('react'); return React.createElement( 'View', { testID: 'heap-ignore', ...props, }, children ); }, })); // Mock iOS codegen components jest.mock('../../../core/specs/CSQMaskedViewNativeComponent', () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const React = require('react'); return { __esModule: true, default: React.forwardRef((props: any, ref: any) => { return React.createElement( 'View', { ...props, ref, testID: 'csq-masked-view', }, props.children ); }), }; }); jest.mock('../../../core/specs/CSQUnmaskedViewNativeComponent', () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const React = require('react'); return { __esModule: true, default: React.forwardRef((props: any, ref: any) => { return React.createElement( 'View', { ...props, ref, testID: 'csq-unmasked-view', }, props.children ); }), }; }); // Mock Android wrapper components jest.mock('../../../replay/csqMasking/CSQMaskedView', () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const React = require('react'); return React.forwardRef((props: any, ref: any) => { return React.createElement( 'View', { ...props, ref, testID: 'csq-masked-view', }, props.children ); }); }); jest.mock('../../../replay/csqMasking/CSQUnmaskedView', () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const React = require('react'); return React.forwardRef((props: any, ref: any) => { return React.createElement( 'View', { ...props, ref, testID: 'csq-unmasked-view', }, props.children ); }); }); describe('withCSQMask Higher-Order Component', () => { beforeEach(() => { jest.clearAllMocks(); }); const TestComponent: React.FC<{ testProp?: string; children?: React.ReactNode; }> = ({ testProp, children }) => ( {testProp || 'Default'} {children} ); TestComponent.displayName = 'TestComponent'; describe('Basic HoC functionality', () => { it('should wrap component with CSQMask functionality', () => { const WrappedComponent = withCSQMask(TestComponent); const { getByTestId } = render(); expect(getByTestId('heap-ignore')).toBeTruthy(); expect(getByTestId('test-component')).toBeTruthy(); }); it('should render masked by default', () => { const WrappedComponent = withCSQMask(TestComponent); const { getByTestId } = render(); expect(getByTestId('csq-masked-view')).toBeTruthy(); }); it('should render unmasked when isSessionReplayMasked is false', () => { const WrappedComponent = withCSQMask(TestComponent, { isSessionReplayMasked: false, }); const { getByTestId } = render(); expect(getByTestId('csq-unmasked-view')).toBeTruthy(); }); it('should render masked when isSessionReplayMasked is true', () => { const WrappedComponent = withCSQMask(TestComponent, { isSessionReplayMasked: true, }); const { getByTestId } = render(); expect(getByTestId('csq-masked-view')).toBeTruthy(); }); }); describe('Props forwarding', () => { it('should forward props to wrapped component', () => { const WrappedComponent = withCSQMask(TestComponent); const { getByText } = render( ); expect(getByText('Custom Value')).toBeTruthy(); }); it('should forward children to wrapped component', () => { const WrappedComponent = withCSQMask(TestComponent); const { getByText } = render( Child Content ); expect(getByText('Child Content')).toBeTruthy(); }); }); describe('HeapIgnore props configuration', () => { it('should apply custom allow* props', () => { const WrappedComponent = withCSQMask(TestComponent, { allowText: true, allowInnerHierarchy: true, allowProps: false, allowInteraction: true, allowAccessibilityLabel: false, }); const { getByTestId } = render(); const heapIgnore = getByTestId('heap-ignore'); expect(heapIgnore.props.allowText).toBe(true); expect(heapIgnore.props.allowInnerHierarchy).toBe(true); expect(heapIgnore.props.allowProps).toBe(false); expect(heapIgnore.props.allowInteraction).toBe(true); expect(heapIgnore.props.allowAccessibilityLabel).toBe(false); }); }); describe('Display name', () => { it('should generate correct display name from component name', () => { const WrappedComponent = withCSQMask(TestComponent); expect(WrappedComponent.displayName).toBe('withCSQMask(TestComponent)'); }); it('should use default name when component has no display name', () => { const AnonymousComponent = () => ; const WrappedComponent = withCSQMask(AnonymousComponent); expect(WrappedComponent.displayName).toBe( 'withCSQMask(AnonymousComponent)' ); }); it('should use component displayName if available', () => { const ComponentWithDisplayName: React.FC = () => ; ComponentWithDisplayName.displayName = 'MyCustomComponent'; const WrappedComponent = withCSQMask(ComponentWithDisplayName); expect(WrappedComponent.displayName).toBe( 'withCSQMask(MyCustomComponent)' ); }); }); describe('Ref forwarding', () => { it('should forward ref to wrapped component', () => { const RefComponent = React.forwardRef( (props, ref) => ( {props.testProp} ) ); RefComponent.displayName = 'RefComponent'; const WrappedComponent = withCSQMask(RefComponent); const ref = React.createRef(); render(); expect(ref.current).toBeTruthy(); }); }); describe('Nested HoC', () => { it('should handle multiple nested withCSQMask calls', () => { const WrappedOnce = withCSQMask(TestComponent, { isSessionReplayMasked: true, }); const WrappedTwice = withCSQMask(WrappedOnce, { isSessionReplayMasked: false, }); const { getAllByTestId } = render(); // Should have two HeapIgnore components (nested) const heapIgnores = getAllByTestId('heap-ignore'); expect(heapIgnores.length).toBeGreaterThanOrEqual(1); }); }); describe('Component hierarchy', () => { it('should maintain correct hierarchy: HeapIgnore > CSQComponent > WrappedComponent', () => { const WrappedComponent = withCSQMask(TestComponent); const { getByTestId } = render(); const heapIgnore = getByTestId('heap-ignore'); const csqView = getByTestId('csq-masked-view'); const testComponent = getByTestId('test-component'); // Verify hierarchy exists (all components rendered) expect(heapIgnore).toBeTruthy(); expect(csqView).toBeTruthy(); expect(testComponent).toBeTruthy(); }); }); describe('Edge cases', () => { it('should handle component with no children', () => { const NoChildrenComponent: React.FC = () => ; const WrappedComponent = withCSQMask(NoChildrenComponent); const { getByTestId } = render(); expect(getByTestId('no-children')).toBeTruthy(); }); it('should handle component with complex children', () => { const ComplexComponent: React.FC<{ children?: React.ReactNode }> = ({ children, }) => ( Header {children} Footer ); const WrappedComponent = withCSQMask(ComplexComponent); const { getByText } = render( Middle Content ); expect(getByText('Header')).toBeTruthy(); expect(getByText('Middle Content')).toBeTruthy(); expect(getByText('Footer')).toBeTruthy(); }); }); });