import React from 'react'; import { render } from '@testing-library/react'; import { useMediaItem, itemClassname } from '../../../src/static/js/utils/hooks/useMediaItem'; // Mock dependencies used by useMediaItem // @todo: Revisit this jest.mock('../../../src/static/js/utils/stores/', () => ({ PageStore: { get: (_: string) => ({ url: 'https://example.com' }) }, })); jest.mock('../../../src/static/js/components/list-item/includes/items', () => ({ MediaItemAuthor: ({ name }: any) =>
, MediaItemAuthorLink: ({ name, link }: any) => ( ), MediaItemMetaViews: ({ views }: any) => , MediaItemMetaDate: ({ time, dateTime, text }: any) => ( ), MediaItemEditLink: ({ link }: any) => , MediaItemViewLink: ({ link }: any) => , })); // @todo: Revisit this // useItem returns titleComponent, descriptionComponent, thumbnailUrl, UnderThumbWrapper jest.mock('../../../src/static/js/utils/hooks/useItem', () => ({ useItem: (props: any) => ({ titleComponent: () =>

{props.title || 'title'}

, descriptionComponent: () =>

{props.description || 'desc'}

, thumbnailUrl: props.thumb || 'thumb.jpg', UnderThumbWrapper: ({ children }: any) =>
{children}
, }), })); function HookConsumer(props: any) { const [TitleComp, DescComp, thumbUrl, UnderThumbComp, EditComp, MetaComp, ViewComp] = useMediaItem(props); // The hook returns functions/components/values. To satisfy TS, render using React.createElement return (
{typeof TitleComp === 'function' ? React.createElement(TitleComp) : null} {typeof DescComp === 'function' ? React.createElement(DescComp) : null}
{typeof thumbUrl === 'string' ? thumbUrl : ''}
{typeof UnderThumbComp === 'function' ? React.createElement( UnderThumbComp, null, typeof EditComp === 'function' ? React.createElement(EditComp) : null, typeof MetaComp === 'function' ? React.createElement(MetaComp) : null, typeof ViewComp === 'function' ? React.createElement(ViewComp) : null ) : null}
); } describe('utils/hooks', () => { describe('useMediaItem', () => { describe('itemClassname utility function', () => { test('Returns default classname when no modifications', () => { expect(itemClassname('base', '', false)).toBe('base'); }); test('Appends inherited classname when provided', () => { expect(itemClassname('base', 'extra', false)).toBe('base extra'); }); test('Appends pl-active-item when isActiveInPlaylistPlayback is true', () => { expect(itemClassname('base', '', true)).toBe('base pl-active-item'); }); test('Appends both inherited classname and active state', () => { expect(itemClassname('base', 'extra', true)).toBe('base extra pl-active-item'); }); }); describe('Basic Rendering', () => { test('Renders basic components from useItem and edit/view links', () => { // @todo: Revisit this const props = { title: 'My Title', description: 'My Desc', thumbnail: 'thumb.jpg', link: '/watch/1', singleLinkContent: true, // hasMediaViewer:... // hasMediaViewerDescr:... // meta_description:... // onMount:... // type:... // ------------------------------ editLink: '/edit/1', showSelection: true, // publishLink: ... // hideAuthor:... author_name: 'Author', author_link: '/u/author', // hideViews:... views: 10, // hideDate:... publish_date: '2020-01-01T00:00:00Z', // hideAllMeta:... }; const { getByTestId, queryByTestId } = render(); expect(getByTestId('title').textContent).toBe(props.title); expect(getByTestId('desc').textContent).toBe(props.description); expect(getByTestId('thumb').textContent).toBe('thumb.jpg'); expect(getByTestId('edit').getAttribute('href')).toBe(props.editLink); expect(getByTestId('views').getAttribute('data-views')).toBe(props.views.toString()); expect(getByTestId('date')).toBeTruthy(); expect(getByTestId('view').getAttribute('href')).toBe(props.link); expect(queryByTestId('author')).toBeTruthy(); }); }); describe('View Link Selection', () => { test('Uses publishLink when provided and showSelection=true', () => { const props = { editLink: '/edit/2', link: '/watch/2', publishLink: '/publish/2', showSelection: true, singleLinkContent: true, author_name: 'A', author_link: '', views: 0, publish_date: 0, }; const { getByTestId } = render(); expect(getByTestId('view').getAttribute('href')).toBe(props.publishLink); }); }); describe('Visibility Controls', () => { test('Hides author, views, and date based on props', () => { const props = { editLink: '/e', link: '/l', showSelection: true, hideAuthor: true, hideViews: true, hideDate: true, publish_date: '2020-01-01T00:00:00Z', views: 5, author_name: 'Hidden', author_link: '/u/x', }; const { queryByTestId } = render(); expect(queryByTestId('author')).toBeNull(); expect(queryByTestId('views')).toBeNull(); expect(queryByTestId('date')).toBeNull(); }); test('Author link resolves using formatInnerLink and PageStore base url when singleLinkContent=false', () => { const props = { editLink: '/e', link: '/l', showSelection: true, singleLinkContent: false, hideAuthor: false, author_name: 'John', author_link: '/u/john', publish_date: '2020-01-01T00:00:00Z', }; const { container } = render(); const a = container.querySelector('[data-testid="author-link"]') as HTMLAnchorElement; expect(a).toBeTruthy(); expect(a.getAttribute('href')).toBe(`https://example.com${props.author_link}`); expect(a.getAttribute('data-name')).toBe(props.author_name); }); }); describe('Meta Visibility', () => { test('Meta wrapper hidden when hideAllMeta=true', () => { const props = { editLink: '/e', link: '/l', showSelection: true, hideAllMeta: true, publish_date: '2020-01-01T00:00:00Z', }; const { queryByTestId } = render(); expect(queryByTestId('author')).toBeNull(); expect(queryByTestId('views')).toBeNull(); expect(queryByTestId('date')).toBeNull(); }); test('Meta wrapper hidden individually by hideAuthor, hideViews, hideDate', () => { const props = { editLink: '/e', link: '/l', showSelection: true, hideAuthor: true, hideViews: false, hideDate: false, publish_date: '2020-01-01T00:00:00Z', views: 5, author_name: 'Test', author_link: '/u/test', }; const { queryByTestId } = render(); expect(queryByTestId('author')).toBeNull(); expect(queryByTestId('views')).toBeTruthy(); expect(queryByTestId('date')).toBeTruthy(); }); }); describe('Edge Cases & Date Handling', () => { test('Handles views when hideViews is false', () => { const props = { editLink: '/e', link: '/l', showSelection: true, hideViews: false, views: 100, publish_date: '2020-01-01T00:00:00Z', author_name: 'A', author_link: '/u/a', }; const { getByTestId } = render(); expect(getByTestId('views')).toBeTruthy(); expect(getByTestId('views').getAttribute('data-views')).toBe('100'); }); test('Renders without showSelection', () => { const props = { editLink: '/e', link: '/l', showSelection: false, publish_date: '2020-01-01T00:00:00Z', author_name: 'A', author_link: '/u/a', }; const { queryByTestId } = render(); expect(queryByTestId('view')).toBeNull(); }); test('Handles numeric publish_date correctly', () => { const props = { editLink: '/e', link: '/l', showSelection: true, publish_date: 1577836800000, // 2020-01-01 as timestamp author_name: 'A', author_link: '/u/a', }; const { getByTestId } = render(); expect(getByTestId('date')).toBeTruthy(); }); test('Handles empty author_link by setting it to null', () => { const props = { editLink: '/e', link: '/l', showSelection: true, singleLinkContent: false, author_name: 'Anonymous', author_link: '', // Empty link publish_date: '2020-01-01T00:00:00Z', }; const { container } = render(); const authorLink = container.querySelector('[data-testid="author-link"]') as HTMLAnchorElement; expect(authorLink).toBeTruthy(); expect(authorLink.getAttribute('href')).toBeNull(); }); }); }); });