Include canonical <link> for user review pages (#13127)
* Include canonical <link> for user review pages Also add rel=nofollow to links to it filtering user reviews by score as it's useless for search engines to visit, it's the same content but filtered.
This commit is contained in:
Родитель
c5c73838af
Коммит
7b9f6fe7f4
|
@ -151,6 +151,7 @@ export class RatingsByStarBase extends React.Component<InternalProps> {
|
|||
<Link
|
||||
className="RatingsByStar-row"
|
||||
key={star}
|
||||
rel="nofollow"
|
||||
title={getLinkTitles(star, starCount) || ''}
|
||||
to={reviewListURL({
|
||||
addonSlug: addon.slug,
|
||||
|
|
|
@ -11,6 +11,7 @@ import { DEFAULT_API_PAGE_SIZE } from 'amo/api';
|
|||
import AddonReviewCard from 'amo/components/AddonReviewCard';
|
||||
import AddonSummaryCard from 'amo/components/AddonSummaryCard';
|
||||
import FeaturedAddonReview from 'amo/components/FeaturedAddonReview';
|
||||
import HeadLinks from 'amo/components/HeadLinks';
|
||||
import Page from 'amo/components/Page';
|
||||
import { fetchReviewPermissions, fetchReviews } from 'amo/actions/reviews';
|
||||
import { setViewContext } from 'amo/actions/viewContext';
|
||||
|
@ -332,6 +333,7 @@ export class AddonReviewListBase extends React.Component<InternalProps> {
|
|||
{reviewId && <meta name="robots" content="noindex, follow" />}
|
||||
</Helmet>
|
||||
)}
|
||||
{addon && !reviewId && <HeadLinks />}
|
||||
|
||||
{errorHandler.renderErrorIfPresent()}
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ describe(__filename, () => {
|
|||
'href',
|
||||
`/en-US/android${reviewListURL({ addonSlug: addon.slug, score })}`,
|
||||
);
|
||||
expect(link).toHaveAttribute('rel', 'nofollow');
|
||||
expect(within(link).getByText(count)).toBeInTheDocument();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import config from 'config';
|
||||
import { waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
|
@ -17,6 +18,7 @@ import {
|
|||
CLIENT_APP_FIREFOX,
|
||||
SET_VIEW_CONTEXT,
|
||||
} from 'amo/constants';
|
||||
import { hrefLangs } from 'amo/languages';
|
||||
import { fetchAddon, loadAddon } from 'amo/reducers/addons';
|
||||
import {
|
||||
changeLocation,
|
||||
|
@ -700,6 +702,56 @@ describe(__filename, () => {
|
|||
expect(getElements('meta[name="robots"]')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('renders a canonical link for the list page with alternates', async () => {
|
||||
renderWithAddonAndReviews();
|
||||
|
||||
const getExpectedURL = (locale, app) => {
|
||||
return `${config.get(
|
||||
'baseURL',
|
||||
)}/${locale}/${app}/addon/${defaultSlug}/reviews/`;
|
||||
};
|
||||
|
||||
await waitFor(() =>
|
||||
expect(getElement('link[rel="canonical"]')).toHaveAttribute(
|
||||
'href',
|
||||
getExpectedURL('en-US', 'firefox'),
|
||||
),
|
||||
);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(getElement('link[rel="alternate"]')).toBeInTheDocument(),
|
||||
);
|
||||
|
||||
expect(getElements('link[rel="alternate"]')).toHaveLength(
|
||||
hrefLangs.length,
|
||||
);
|
||||
|
||||
const hrefLangsMap = config.get('hrefLangsMap');
|
||||
hrefLangs.forEach((hrefLang) => {
|
||||
const locale = hrefLangsMap[hrefLang] || hrefLang;
|
||||
expect(
|
||||
getElement(`link[rel="alternate"][hreflang="${hrefLang}"]`),
|
||||
).toHaveAttribute('href', getExpectedURL(locale, 'firefox'));
|
||||
});
|
||||
});
|
||||
|
||||
it('renders a canonical with no query string', async () => {
|
||||
renderWithAddonAndReviews({ score: 5 });
|
||||
|
||||
const getExpectedURL = (locale, app) => {
|
||||
return `${config.get(
|
||||
'baseURL',
|
||||
)}/${locale}/${app}/addon/${defaultSlug}/reviews/`;
|
||||
};
|
||||
|
||||
await waitFor(() =>
|
||||
expect(getElement('link[rel="canonical"]')).toHaveAttribute(
|
||||
'href',
|
||||
getExpectedURL('en-US', 'firefox'),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('renders a robots meta tag when there is a featured review', async () => {
|
||||
const reviews = [
|
||||
{ ...fakeReview, id: 1, score: 1 },
|
||||
|
|
Загрузка…
Ссылка в новой задаче