/** * Disabling `react/jsx-key` lets us pass `children` as an Iterable directly to the test function * instead of needing to wrap everything in a Fragment, * which is not representative of real use-cases */ /* eslint-disable react/jsx-key */ import React, { Fragment } from 'react'; import styled from '@emotion/styled'; import { findChildren } from './findChildren'; // Test components const Foo = React.forwardRef( ({ text }, ref) =>
{text}
, ); Foo.displayName = 'Foo'; const Bar = React.forwardRef( ({ text }, ref) =>
{text}
, ); Bar.displayName = 'Bar'; const Baz = React.forwardRef( ({ text }, ref) =>
{text}
, ); Baz.displayName = 'Baz'; // Add static properties to test components with type assertion (Foo as any).isFoo = true; (Bar as any).isBar = true; (Baz as any).isBaz = true; describe('packages/lib/findChildren', () => { describe('basic functionality', () => { it('should find all children with matching static property', () => { const children = [ , , , , , ]; const found = findChildren(children, 'isFoo'); expect(found).toHaveLength(3); expect(found[0].props.text).toBe('first'); expect(found[1].props.text).toBe('third'); expect(found[2].props.text).toBe('fifth'); }); it('should return empty array if no children match', () => { const children = [, ]; const found = findChildren(children, 'isBaz'); expect(found).toEqual([]); }); it('should find single matching child', () => { const children = [ , , ]; const found = findChildren(children, 'isFoo'); expect(found).toHaveLength(1); expect(found[0].props.text).toBe('only-foo'); }); }); it('should find mapped children', () => { const COUNT = 5; const children = new Array(COUNT).fill(null).map((_, i) => { return ; }); const found = findChildren(children, 'isFoo'); expect(found).toHaveLength(COUNT); }); it('should find deeply mapped children', () => { const COUNT = 5; const children = ( <> {new Array(COUNT).fill(null).map((_, i) => { return ; })} ); const found = findChildren(children, 'isFoo'); expect(found).toHaveLength(COUNT); }); }); describe('empty and null children handling', () => { it('should handle null children', () => { const found = findChildren(null, 'isFoo'); expect(found).toEqual([]); }); it('should handle undefined children', () => { const found = findChildren(undefined, 'isFoo'); expect(found).toEqual([]); }); it('should handle empty fragment', () => { const children = <>; const found = findChildren(children, 'isFoo'); expect(found).toEqual([]); }); it('should handle empty array children', () => { const children: Array = []; const found = findChildren(children, 'isFoo'); expect(found).toEqual([]); }); }); describe('Fragment handling', () => { it('should handle single-level fragment children', () => { const children = ( ); const found = findChildren(children, 'isFoo'); expect(found).toHaveLength(2); expect(found[0].props.text).toBe('foo-in-fragment'); expect(found[1].props.text).toBe('another-foo'); }); it('should NOT find children in deeply nested Fragments', () => { const children = ( ); // Should only find direct children, not double-nested ones const found = findChildren(children, 'isFoo'); expect(found).toHaveLength(1); expect(found[0].props.text).toBe('direct-foo'); }); }); describe('styled components', () => { it('should work with styled components from @emotion/styled', () => { const StyledFoo = styled(Foo)` background-color: red; padding: 8px; `; const children = [ , , , , , ]; const found = findChildren(children, 'isFoo'); expect(found).toHaveLength(4); expect(found.map(c => c.props.text)).toEqual([ 'regular-foo', 'styled-foo', 'styled-foo-two', 'another-foo', ]); // Verify the styled component is actually styled const styledComponent = found[1]; const styledType = styledComponent.type as any; const hasEmotionProps = !!(styledType.target || styledType.__emotion_base); expect(hasEmotionProps).toBe(true); }); }); describe('search depth limitations', () => { it('should NOT find deeply nested components', () => { const children = [ , ,
, , ]; const found = findChildren(children, 'isFoo'); expect(found).toHaveLength(1); expect(found[0].props.text).toBe('direct-child'); }); });