Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,11 @@ microCMSの`blog` APIに以下のフィールドを追加する。
| フィールドID | 種類 | 設定 |
| ------------- | -------- | --------------------- |
| `isSponsored` | 真偽値 | 初期値を`false`にする |
| `sponsorName` | テキスト | 広告主の正式名称 |
| `sponsorUrl` | テキスト | 広告主の公式URL |

`isSponsored`を有効にした記事では、一覧と記事上部にPR表示が追加される。本文中のリンクは、`sponsorUrl`と同じドメインまたはそのサブドメインに限り`rel="sponsored"`が付与される。
`isSponsored`を有効にした記事では、一覧と記事上部にPR表示が追加され、記事上部に「本記事は、広告主から依頼を受けて制作した広告です。」と表示される。本文中のリンクは、`sponsorUrl`と同じドメインまたはそのサブドメインに限り`rel="sponsored"`が付与される。

スポンサー記事では`sponsorName`と有効な`sponsorUrl`が必須となり、不足している場合はビルドが失敗する。
スポンサー記事では有効な`sponsorUrl`が必須となり、不足している場合はビルドが失敗する。

スポンサー記事は、初回公開時のOneSignalプッシュ通知から自動的に除外される。

Expand Down
1 change: 0 additions & 1 deletion e2e/fixtures/content.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ const createArticle = (index, baseUrl) => {
},
],
isSponsored: index === 1,
sponsorName: index === 1 ? 'Example Sponsor' : undefined,
sponsorUrl: index === 1 ? 'https://sponsor.example' : undefined,
createdAt: publishedAt,
publishedAt,
Expand Down
4 changes: 1 addition & 3 deletions e2e/sponsored.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ test('discloses sponsored articles and marks only sponsor links', async ({ page
await sponsoredCard.click();

await expect(page.getByText('PR', { exact: true })).toBeVisible();
await expect(
page.getByText('本記事は、Example Sponsorから依頼を受けて制作した広告です。'),
).toBeVisible();
await expect(page.getByText('本記事は、広告主から依頼を受けて制作した広告です。')).toBeVisible();
await expect(page.getByRole('link', { name: 'スポンサーリンク' })).toHaveAttribute(
'rel',
'sponsored',
Expand Down
5 changes: 2 additions & 3 deletions src/components/Common/SponsoredDisclosure/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ import {
} from '@/styles/designTokens';

type Props = {
sponsorName?: string;
compact?: boolean;
};

export default function SponsoredDisclosure({ sponsorName, compact = false }: Props) {
export default function SponsoredDisclosure({ compact = false }: Props) {
const { theme } = useTheme();
const badgeClassName = `${styles.badge} ${radiusClassNames.control} ${colorClassNames.accentBadge}`;

Expand All @@ -34,7 +33,7 @@ export default function SponsoredDisclosure({ sponsorName, compact = false }: Pr
return (
<aside className={disclosureClassName} aria-label="広告に関する表示">
<span className={badgeClassName}>PR</span>
<span>本記事は、{sponsorName}から依頼を受けて制作した広告です。</span>
<span>本記事は、広告主から依頼を受けて制作した広告です。</span>
</aside>
);
}
3 changes: 1 addition & 2 deletions src/components/Features/Article/__tests__/Article.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,14 @@ describe('ArticleFeature', () => {
it('shows a clear disclosure for sponsored articles', () => {
const article = createArticle({
isSponsored: true,
sponsorName: 'Example Sponsor',
sponsorUrl: 'https://sponsor.example',
});

render(<ArticleFeature data={article} relatedArticles={[]} />);

expect(screen.getByText('PR')).toBeInTheDocument();
expect(
screen.getByText('本記事は、Example Sponsorから依頼を受けて制作した広告です。'),
screen.getByText('本記事は、広告主から依頼を受けて制作した広告です。'),
).toBeInTheDocument();
});

Expand Down
2 changes: 1 addition & 1 deletion src/components/Features/Article/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export default function ArticleFeature({ data, relatedArticles }: Props) {
<h1 className={`${styles.title} text-3xl font-bold lg:text-3xl`} data-article-title>
{data.title}
</h1>
{data.isSponsored && <SponsoredDisclosure sponsorName={data.sponsorName} />}
{data.isSponsored && <SponsoredDisclosure />}
<WebpImage article={data} priority />
<DoubleDate article={data} articleMode={true} />
<AdAlert />
Expand Down
7 changes: 3 additions & 4 deletions src/libs/__tests__/microcms.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('microcms client helpers', () => {
await expect(getDetail('article-a', queries)).resolves.toEqual({ id: 'article-a' });

const blogQueries = {
fields: 'id,title,isSponsored,sponsorName,sponsorUrl',
fields: 'id,title,isSponsored,sponsorUrl',
};

expect(microcmsSdkMock.client.getAllContents).toHaveBeenCalledWith({
Expand All @@ -71,11 +71,10 @@ describe('microcms client helpers', () => {
microcmsSdkMock.client.getListDetail.mockResolvedValue({
title: 'Sponsored article',
isSponsored: true,
sponsorName: '',
sponsorUrl: 'https://sponsor.example',
sponsorUrl: '',
});

await expect(getDetail('article-a')).rejects.toThrow(/sponsorName/);
await expect(getDetail('article-a')).rejects.toThrow(/sponsorUrl/);
});

it('delegates category helpers to the categories endpoint', async () => {
Expand Down
1 change: 0 additions & 1 deletion src/types/microcms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export type Blog = {
introduction_blocks: IntroductionBlock[];
content_blocks: ContentBlock[];
isSponsored?: boolean;
sponsorName?: string;
sponsorUrl?: string;
};

Expand Down
19 changes: 5 additions & 14 deletions src/utils/__tests__/sponsored.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,27 @@ describe('sponsored article utilities', () => {
expect(mergeSponsoredRel('sponsored')).toBe('sponsored');
});

it('requires a sponsor name and valid URL only for sponsored articles', () => {
it('requires a valid sponsor URL only for sponsored articles', () => {
expect(() => assertValidSponsoredArticle(createArticle())).not.toThrow();
expect(() =>
assertValidSponsoredArticle(
createArticle({ isSponsored: true, sponsorUrl: 'https://sponsor.example' }),
),
).toThrow(/sponsorName/);
expect(() =>
assertValidSponsoredArticle(
createArticle({ isSponsored: true, sponsorName: 'Example Sponsor' }),
),
).toThrow(/sponsorUrl/);
expect(() => assertValidSponsoredArticle(createArticle({ isSponsored: true }))).toThrow(
/sponsorUrl/,
);
expect(() =>
assertValidSponsoredArticle(
createArticle({
isSponsored: true,
sponsorName: 'Example Sponsor',
sponsorUrl: 'https://sponsor.example',
}),
),
).not.toThrow();
});

it('includes sponsored fields in partial microCMS queries', () => {
expect(includeSponsoredFields('id,title')).toBe('id,title,isSponsored,sponsorName,sponsorUrl');
expect(includeSponsoredFields('id,title')).toBe('id,title,isSponsored,sponsorUrl');
expect(includeSponsoredFields(['id', 'title'])).toEqual([
'id',
'title',
'isSponsored',
'sponsorName',
'sponsorUrl',
]);
expect(includeSponsoredFields('')).toBe('');
Expand Down
6 changes: 1 addition & 5 deletions src/utils/sponsored.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { CheerioAPI } from 'cheerio';
import type { Blog } from '@/types/microcms';

const SPONSORED_REL_VALUE = 'sponsored';
const SPONSORED_FIELDS = ['isSponsored', 'sponsorName', 'sponsorUrl'] as const;
const SPONSORED_FIELDS = ['isSponsored', 'sponsorUrl'] as const;

const normalizeHostname = (hostname: string) => hostname.toLowerCase().replace(/^www\./, '');

Expand Down Expand Up @@ -57,10 +57,6 @@ export const assertValidSponsoredArticle = (article: Blog) => {
return;
}

if (!article.sponsorName?.trim()) {
throw new Error(`Sponsored article "${article.title}" requires sponsorName`);
}

if (!article.sponsorUrl?.trim() || !parseHttpUrl(article.sponsorUrl)) {
throw new Error(`Sponsored article "${article.title}" requires a valid sponsorUrl`);
}
Expand Down
Loading