import React from 'react';
import { render, screen } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { useSelector } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import { getConfig } from '@edx/frontend-platform';
import { AvatarOutlineAndLabelColors, ThreadType } from '../../../data/constants';
import DiscussionContext from '../../common/context';
import { useAlertBannerVisible } from '../../data/hooks';
import PostHeader, { PostAvatar } from './PostHeader';
jest.mock('react-redux', () => ({ useSelector: jest.fn() }));
jest.mock('@edx/frontend-platform', () => ({ getConfig: jest.fn() }));
jest.mock('../../data/hooks', () => ({ useAlertBannerVisible: jest.fn() }));
const defaultPostUsers = {
'test-user': {
profile: { image: { hasImage: true, imageUrlSmall: 'http://avatar.test/img.png' } },
},
};
const ctxValue = { courseId: 'course-v1:edX+DemoX+Demo_Course', enableInContextSidebar: false };
function renderWithContext(ui) {
return render(
{ui}
,
);
}
describe('PostAvatar', () => {
beforeEach(() => {
jest.clearAllMocks();
useSelector.mockReturnValue({ imageUrlSmall: 'http://redux-avatar.png' });
getConfig.mockReturnValue({ ENABLE_PROFILE_IMAGE: 'true' });
});
it('renders avatar with profile image when ENABLE_PROFILE_IMAGE=true', () => {
renderWithContext(
,
);
const avatarImg = screen.getByAltText('test-user');
expect(avatarImg).toHaveAttribute('src', 'http://avatar.test/img.png');
});
it('falls back to redux avatar if no profile image', () => {
renderWithContext(
,
);
const avatarImg = screen.getByAltText('test-user');
expect(avatarImg).toHaveAttribute('src', 'http://redux-avatar.png');
});
it('applies Staff outline class if authorLabel provided', () => {
renderWithContext(
,
);
const avatar = screen.getByAltText('test-user');
expect(avatar.className).toMatch(`outline-${AvatarOutlineAndLabelColors.Staff}`);
});
it('applies anonymous outline class if no authorLabel', () => {
const { container } = renderWithContext(
,
);
expect(container.querySelector('.outline-anonymous')).toBeInTheDocument();
});
});
describe('PostHeader', () => {
beforeEach(() => {
jest.clearAllMocks();
useSelector.mockReturnValue({ imageUrlSmall: 'http://redux-avatar.png' });
getConfig.mockReturnValue({ ENABLE_PROFILE_IMAGE: 'true' });
useAlertBannerVisible.mockReturnValue(false);
});
const renderHeader = (props = {}) => renderWithContext(
,
);
it('renders post title and author', () => {
renderHeader();
expect(screen.getByText('Sample Post Title')).toBeInTheDocument();
expect(screen.getByText('test-user')).toBeInTheDocument();
});
it('adds answered badge for endorsed QUESTION preview', () => {
renderHeader({ postType: ThreadType.QUESTION, hasEndorsed: true, preview: true });
expect(screen.getByText(/answered/i)).toBeInTheDocument();
});
it('adds mt-10px class if alert banner is visible', () => {
useAlertBannerVisible.mockReturnValue(true);
const { container } = renderHeader({ preview: false });
expect(container.firstChild).toHaveClass('mt-10px');
});
it('falls back to anonymous if no author provided', () => {
renderHeader({ author: '' });
expect(screen.getByText(/anonymous/i)).toBeInTheDocument();
});
});