mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-02-08 08:22:59 -05:00
feat: utils/hooks unit tests
This commit is contained in:
380
frontend/tests/utils/hooks/useItem.test.tsx
Normal file
380
frontend/tests/utils/hooks/useItem.test.tsx
Normal file
@@ -0,0 +1,380 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { useItem } from '../../../src/static/js/utils/hooks/useItem';
|
||||
|
||||
// Mock the item components
|
||||
jest.mock('../../../src/static/js/components/list-item/includes/items', () => ({
|
||||
ItemDescription: ({ description }: { description: string }) => (
|
||||
<div data-testid="item-description">{description}</div>
|
||||
),
|
||||
ItemMain: ({ children }: { children: React.ReactNode }) => <div data-testid="item-main">{children}</div>,
|
||||
ItemMainInLink: ({ children, link, title }: { children: React.ReactNode; link: string; title: string }) => (
|
||||
<div data-testid="item-main-in-link" data-link={link} data-title={title}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
ItemTitle: ({ title, ariaLabel }: { title: string; ariaLabel: string }) => (
|
||||
<h3 data-testid="item-title" data-aria-label={ariaLabel}>
|
||||
{title}
|
||||
</h3>
|
||||
),
|
||||
ItemTitleLink: ({ title, link, ariaLabel }: { title: string; link: string; ariaLabel: string }) => (
|
||||
<h3 data-testid="item-title-link" data-link={link} data-aria-label={ariaLabel}>
|
||||
{title}
|
||||
</h3>
|
||||
),
|
||||
}));
|
||||
|
||||
// Mock PageStore
|
||||
jest.mock('../../../src/static/js/utils/stores/PageStore.js', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
get: (key: string) => (key === 'config-site' ? { url: 'https://example.com' } : null),
|
||||
},
|
||||
}));
|
||||
|
||||
// HookConsumer component to test the hook
|
||||
function HookConsumer(props: any) {
|
||||
const { titleComponent, descriptionComponent, thumbnailUrl, UnderThumbWrapper } = useItem(props);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div data-testid="title">{titleComponent()}</div>
|
||||
<div data-testid="description">{descriptionComponent()}</div>
|
||||
<div data-testid="thumbnail-url">{thumbnailUrl || 'null'}</div>
|
||||
<div data-testid="wrapper-type">{(UnderThumbWrapper as any).name}</div>
|
||||
<div data-testid="wrapper-component">
|
||||
<div>Wrapper content</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Wrapper consumer to test wrapper selection
|
||||
function WrapperTest(props: any) {
|
||||
const { UnderThumbWrapper } = useItem(props);
|
||||
|
||||
return (
|
||||
<UnderThumbWrapper link={props.link} title={props.title} data-testid="wrapper-test">
|
||||
<span data-testid="wrapper-content">Content</span>
|
||||
</UnderThumbWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
describe('utils/hooks', () => {
|
||||
describe('useItem', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('titleComponent Rendering', () => {
|
||||
test('Renders ItemTitle when singleLinkContent is true', () => {
|
||||
const { getByTestId } = render(
|
||||
<HookConsumer
|
||||
title="Test Title"
|
||||
description="Test Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
singleLinkContent={true}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(getByTestId('title').querySelector('[data-testid="item-title"]')).toBeTruthy();
|
||||
expect(getByTestId('title').querySelector('[data-testid="item-title-link"]')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('Renders ItemTitleLink when singleLinkContent is false', () => {
|
||||
const { getByTestId } = render(
|
||||
<HookConsumer
|
||||
title="Test Title"
|
||||
description="Test Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
singleLinkContent={false}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(getByTestId('title').querySelector('[data-testid="item-title"]')).toBeFalsy();
|
||||
expect(getByTestId('title').querySelector('[data-testid="item-title-link"]')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Renders with default link when singleLinkContent is not provided', () => {
|
||||
const { getByTestId } = render(
|
||||
<HookConsumer title="Test Title" description="Test Description" link="/media/test" thumbnail="" />
|
||||
);
|
||||
|
||||
// Default is false for singleLinkContent
|
||||
expect(getByTestId('title').querySelector('[data-testid="item-title-link"]')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('descriptionComponent Rendering', () => {
|
||||
test('Renders single ItemDescription when hasMediaViewer is false', () => {
|
||||
const { getByTestId, queryAllByTestId } = render(
|
||||
<HookConsumer
|
||||
title="Test Title"
|
||||
description="My Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
hasMediaViewer={false}
|
||||
/>
|
||||
);
|
||||
|
||||
const descriptions = queryAllByTestId('item-description');
|
||||
expect(descriptions.length).toBe(1);
|
||||
expect(descriptions[0].textContent).toBe('My Description');
|
||||
});
|
||||
|
||||
test('Renders single ItemDescription when hasMediaViewerDescr is false', () => {
|
||||
const { getByTestId, queryAllByTestId } = render(
|
||||
<HookConsumer
|
||||
title="Test Title"
|
||||
description="My Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
hasMediaViewer={true}
|
||||
hasMediaViewerDescr={false}
|
||||
/>
|
||||
);
|
||||
|
||||
const descriptions = queryAllByTestId('item-description');
|
||||
expect(descriptions.length).toBe(1);
|
||||
expect(descriptions[0].textContent).toBe('My Description');
|
||||
});
|
||||
|
||||
test('Renders two ItemDescriptions when hasMediaViewer and hasMediaViewerDescr are both true', () => {
|
||||
const { queryAllByTestId } = render(
|
||||
<HookConsumer
|
||||
title="Test Title"
|
||||
description="Main Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
hasMediaViewer={true}
|
||||
hasMediaViewerDescr={true}
|
||||
meta_description="Meta Description"
|
||||
/>
|
||||
);
|
||||
|
||||
const descriptions = queryAllByTestId('item-description');
|
||||
expect(descriptions.length).toBe(2);
|
||||
expect(descriptions[0].textContent).toBe('Meta Description');
|
||||
expect(descriptions[1].textContent).toBe('Main Description');
|
||||
});
|
||||
|
||||
test('Trims description text', () => {
|
||||
const { queryAllByTestId } = render(
|
||||
<HookConsumer
|
||||
title="Test Title"
|
||||
description=" Description with spaces "
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
/>
|
||||
);
|
||||
|
||||
expect(queryAllByTestId('item-description')[0].textContent).toBe('Description with spaces');
|
||||
});
|
||||
|
||||
test('Trims meta_description text', () => {
|
||||
const { queryAllByTestId } = render(
|
||||
<HookConsumer
|
||||
title="Test Title"
|
||||
description="Main Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
hasMediaViewer={true}
|
||||
hasMediaViewerDescr={true}
|
||||
meta_description=" Meta with spaces "
|
||||
/>
|
||||
);
|
||||
|
||||
expect(queryAllByTestId('item-description')[0].textContent).toBe('Meta with spaces');
|
||||
});
|
||||
});
|
||||
|
||||
describe('thumbnailUrl', () => {
|
||||
test('Returns null when thumbnail is empty string', () => {
|
||||
const { getByTestId } = render(
|
||||
<HookConsumer
|
||||
title="Test Title"
|
||||
description="Test Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
/>
|
||||
);
|
||||
|
||||
expect(getByTestId('thumbnail-url').textContent).toBe('null');
|
||||
});
|
||||
|
||||
test('Returns formatted URL when thumbnail has value', () => {
|
||||
const { getByTestId } = render(
|
||||
<HookConsumer
|
||||
title="Test Title"
|
||||
description="Test Description"
|
||||
link="https://example.com"
|
||||
thumbnail="/media/thumbnail.jpg"
|
||||
/>
|
||||
);
|
||||
|
||||
expect(getByTestId('thumbnail-url').textContent).toBe('https://example.com/media/thumbnail.jpg');
|
||||
});
|
||||
|
||||
test('Handles absolute URLs as thumbnails', () => {
|
||||
const { getByTestId } = render(
|
||||
<HookConsumer
|
||||
title="Test Title"
|
||||
description="Test Description"
|
||||
link="https://example.com"
|
||||
thumbnail="https://cdn.example.com/image.jpg"
|
||||
/>
|
||||
);
|
||||
|
||||
// formatInnerLink should preserve absolute URLs
|
||||
expect(getByTestId('thumbnail-url').textContent).toBe('https://cdn.example.com/image.jpg');
|
||||
});
|
||||
});
|
||||
|
||||
describe('UnderThumbWrapper', () => {
|
||||
test('Uses ItemMainInLink when singleLinkContent is true', () => {
|
||||
const { getByTestId } = render(
|
||||
<WrapperTest
|
||||
title="Test Title"
|
||||
description="Test Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
singleLinkContent={true}
|
||||
/>
|
||||
);
|
||||
|
||||
// When singleLinkContent is true, UnderThumbWrapper should be ItemMainInLink
|
||||
expect(getByTestId('item-main-in-link')).toBeTruthy();
|
||||
expect(getByTestId('item-main-in-link').getAttribute('data-link')).toBe('https://example.com');
|
||||
expect(getByTestId('item-main-in-link').getAttribute('data-title')).toBe('Test Title');
|
||||
});
|
||||
|
||||
test('Uses ItemMain when singleLinkContent is false', () => {
|
||||
const { getByTestId } = render(
|
||||
<WrapperTest
|
||||
title="Test Title"
|
||||
description="Test Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
singleLinkContent={false}
|
||||
/>
|
||||
);
|
||||
|
||||
// When singleLinkContent is false, UnderThumbWrapper should be ItemMain
|
||||
expect(getByTestId('item-main')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Uses ItemMain by default when singleLinkContent is not provided', () => {
|
||||
const { getByTestId } = render(
|
||||
<WrapperTest
|
||||
title="Test Title"
|
||||
description="Test Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
/>
|
||||
);
|
||||
|
||||
// Default is singleLinkContent=false, so ItemMain
|
||||
expect(getByTestId('item-main')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('onMount callback', () => {
|
||||
test('Calls onMount callback when component mounts', () => {
|
||||
const onMountCallback = jest.fn();
|
||||
|
||||
render(
|
||||
<HookConsumer
|
||||
title="Test Title"
|
||||
description="Test Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
onMount={onMountCallback}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(onMountCallback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('Calls onMount only once on initial mount', () => {
|
||||
const onMountCallback = jest.fn();
|
||||
|
||||
const { rerender } = render(
|
||||
<HookConsumer
|
||||
title="Test Title"
|
||||
description="Test Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
onMount={onMountCallback}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(onMountCallback).toHaveBeenCalledTimes(1);
|
||||
|
||||
rerender(
|
||||
<HookConsumer
|
||||
title="Updated Title"
|
||||
description="Updated Description"
|
||||
link="https://example.com"
|
||||
thumbnail=""
|
||||
onMount={onMountCallback}
|
||||
/>
|
||||
);
|
||||
|
||||
// Should still be called only once (useEffect with empty dependency array)
|
||||
expect(onMountCallback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Integration tests', () => {
|
||||
test('Complete rendering with all props', () => {
|
||||
const onMount = jest.fn();
|
||||
const { getByTestId, queryAllByTestId } = render(
|
||||
<HookConsumer
|
||||
title="Complete Test"
|
||||
description="Complete Description"
|
||||
link="/media/complete"
|
||||
thumbnail="/img/thumb.jpg"
|
||||
type="media"
|
||||
hasMediaViewer={true}
|
||||
hasMediaViewerDescr={true}
|
||||
meta_description="Complete Meta"
|
||||
singleLinkContent={false}
|
||||
onMount={onMount}
|
||||
/>
|
||||
);
|
||||
|
||||
const descriptions = queryAllByTestId('item-description');
|
||||
expect(descriptions.length).toBe(2);
|
||||
expect(onMount).toHaveBeenCalledTimes(1);
|
||||
expect(getByTestId('thumbnail-url').textContent).toBe('https://example.com/img/thumb.jpg');
|
||||
});
|
||||
|
||||
test('Minimal props required', () => {
|
||||
const { getByTestId } = render(
|
||||
<HookConsumer title="Title" description="Description" link="/link" thumbnail="" />
|
||||
);
|
||||
|
||||
expect(getByTestId('title')).toBeTruthy();
|
||||
expect(getByTestId('description')).toBeTruthy();
|
||||
expect(getByTestId('thumbnail-url').textContent).toBe('null');
|
||||
});
|
||||
|
||||
test('Renders with special characters in title and description', () => {
|
||||
const { queryAllByTestId } = render(
|
||||
<HookConsumer
|
||||
title="Title with & < > special chars"
|
||||
description={`Description with 'quotes' and "double quotes"`}
|
||||
link="/media"
|
||||
thumbnail=""
|
||||
/>
|
||||
);
|
||||
|
||||
const descriptions = queryAllByTestId('item-description');
|
||||
expect(descriptions[0].textContent).toContain('Description with');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user