diff --git a/client/blocks/reader-full-post/header-meta.jsx b/client/blocks/reader-full-post/header-meta.jsx index bfd5b257b6dd..784d6d7bcf3d 100644 --- a/client/blocks/reader-full-post/header-meta.jsx +++ b/client/blocks/reader-full-post/header-meta.jsx @@ -1,25 +1,29 @@ import { TimeSince } from '@automattic/components'; import PropTypes from 'prop-types'; +import { useSelector } from 'react-redux'; import ReaderAuthorLink from 'calypso/blocks/reader-author-link'; import ReaderSiteStreamLink from 'calypso/blocks/reader-site-stream-link'; import UserAvatar from 'calypso/blocks/user-avatar'; import { areEqualIgnoringWhitespaceAndCase } from 'calypso/lib/string'; import { getStreamUrl } from 'calypso/reader/route'; +import { getFeed } from 'calypso/state/reader/feeds/selectors'; const ReaderFullPostHeaderMeta = ( { post, author, siteName, feedId, siteId } ) => { const streamUrl = getStreamUrl( feedId, siteId ); - + const feed = useSelector( ( state ) => getFeed( state, feedId ) ); const hasAuthorName = author?.name; const hasMatchingAuthorAndSiteNames = hasAuthorName && areEqualIgnoringWhitespaceAndCase( String( siteName ), String( author?.name ) ); const showAuthorLink = hasAuthorName && ! hasMatchingAuthorAndSiteNames; + const avatarUrl = + ! author.avatar_URL && post.is_external ? feed?.site_icon || feed?.image : author?.avatar_URL; return (
diff --git a/client/blocks/reader-full-post/test/header-meta.jsx b/client/blocks/reader-full-post/test/header-meta.jsx new file mode 100644 index 000000000000..cfb5339fba92 --- /dev/null +++ b/client/blocks/reader-full-post/test/header-meta.jsx @@ -0,0 +1,91 @@ +/** + * @jest-environment jsdom + */ +import { render } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { createStore } from 'redux'; +import UserAvatar from 'calypso/blocks/user-avatar'; +import { getFeed } from 'calypso/state/reader/feeds/selectors'; +import ReaderFullPostHeaderMeta from '../header-meta'; + +jest.mock( '@automattic/components', () => ( { + TimeSince: () => null, +} ) ); + +jest.mock( 'calypso/blocks/user-avatar', () => jest.fn( () => null ) ); + +jest.mock( 'calypso/state/reader/feeds/selectors', () => ( { + getFeed: jest.fn(), +} ) ); + +const createMockStore = () => { + const reducer = ( state = {} ) => state; + return createStore( reducer ); +}; + +const renderHeaderMeta = ( { post, author, siteName, feedId, siteId } = {} ) => { + const store = createMockStore(); + return render( + + + + ); +}; + +describe( 'ReaderFullPostHeaderMeta avatar fallback', () => { + const testAuthor = { name: 'Test Author', avatar_URL: 'https://example.com/author-avatar.png' }; + + beforeEach( () => { + jest.clearAllMocks(); + getFeed.mockReturnValue( undefined ); + } ); + + it( 'keeps author avatar when one already exists', () => { + getFeed.mockReturnValue( { + site_icon: 'https://example.com/site-icon.png', + } ); + + renderHeaderMeta( { + author: testAuthor, + post: { is_external: true }, + } ); + + const avatarProps = UserAvatar.mock.calls[ 0 ][ 0 ]; + expect( avatarProps.user.avatar_URL ).toBe( 'https://example.com/author-avatar.png' ); + } ); + + it( 'uses feed site_icon when author avatar is missing for external posts', () => { + getFeed.mockReturnValue( { + site_icon: 'https://example.com/site-icon.png', + image: 'https://example.com/feed-image.png', + } ); + + renderHeaderMeta( { + post: { is_external: true }, + author: { ...testAuthor, avatar_URL: undefined }, + } ); + + const avatarProps = UserAvatar.mock.calls[ 0 ][ 0 ]; + expect( avatarProps.user.avatar_URL ).toBe( 'https://example.com/site-icon.png' ); + } ); + + it( 'falls back to feed image when feed site_icon is unavailable', () => { + getFeed.mockReturnValue( { + image: 'https://example.com/feed-image.png', + } ); + + renderHeaderMeta( { + post: { is_external: true }, + author: { ...testAuthor, avatar_URL: undefined }, + } ); + + const avatarProps = UserAvatar.mock.calls[ 0 ][ 0 ]; + expect( avatarProps.user.avatar_URL ).toBe( 'https://example.com/feed-image.png' ); + } ); +} );