Skip to content

Commit 28ad533

Browse files
test(promote): adjust breakpoint assertions for mobile-first responsive design
Update breakpoint checks to account for inner container padding changes. Co-Authored-By: Hagicode <noreply@hagicode.com> Signed-off-by: newbe36524 <newbe36524@qq.com>
1 parent 7de74b3 commit 28ad533

3 files changed

Lines changed: 80 additions & 10 deletions

File tree

src/components/__tests__/DocsPromoteInfoBanner.test.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ function createFetchMock(promotions: Array<{
6060
titleEn: string;
6161
descriptionZh: string;
6262
descriptionEn: string;
63+
ctaZh?: string;
64+
ctaEn?: string;
6365
link: string;
6466
platform?: string;
6567
}>) {
@@ -96,6 +98,9 @@ function createFetchMock(promotions: Array<{
9698
id: promotion.id,
9799
title: { zh: promotion.titleZh, en: promotion.titleEn },
98100
description: { zh: promotion.descriptionZh, en: promotion.descriptionEn },
101+
cta: promotion.ctaZh || promotion.ctaEn
102+
? { zh: promotion.ctaZh, en: promotion.ctaEn }
103+
: undefined,
99104
link: promotion.link,
100105
targetPlatform: promotion.platform,
101106
})),
@@ -407,6 +412,8 @@ describe('DocsPromoteBannerController', () => {
407412
titleEn: 'Wishlist Now',
408413
descriptionZh: '游戏将于 2026-04-29 发售,立即前往 Steam 添加愿望单。',
409414
descriptionEn: 'Coming April 29, 2026. Add to your Steam wishlist now!',
415+
ctaZh: '加入愿望单',
416+
ctaEn: 'Wishlist on Steam',
410417
link: 'https://store.steampowered.com/app/4625540/Hagicode/',
411418
platform: 'steam',
412419
},
@@ -423,7 +430,7 @@ describe('DocsPromoteBannerController', () => {
423430
expect(screen.getByText('Steam')).toBeInTheDocument();
424431
const stripButton = screen.getByRole('button', { name: //i });
425432
expect(stripButton).toBeInTheDocument();
426-
expect(screen.getByText('立即查看')).toBeInTheDocument();
433+
expect(screen.getByText('加入愿望单')).toBeInTheDocument();
427434
fireEvent.click(stripButton);
428435
expect(window.open).toHaveBeenCalledWith(
429436
'https://store.steampowered.com/app/4625540/Hagicode/',
@@ -602,6 +609,7 @@ describe('DocsPromoteBannerController', () => {
602609
zh: '游戏将于 2026-04-29 发售,立即前往 Steam 添加愿望单。',
603610
en: 'Coming April 29, 2026. Add to your Steam wishlist now!',
604611
},
612+
cta: { zh: '加入愿望单', en: 'Wishlist on Steam' },
605613
link: 'https://store.steampowered.com/app/4625540/Hagicode/',
606614
targetPlatform: 'steam',
607615
}],

src/lib/docs-promote-banner.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ describe('docs promote banner source', () => {
4949
zh: '游戏将于 2026-04-29 发售,立即前往 Steam 添加愿望单。',
5050
en: 'Coming April 29, 2026. Add to your Steam wishlist now!',
5151
},
52+
cta: { zh: '加入愿望单', en: 'Wishlist on Steam' },
5253
link: 'https://store.steampowered.com/app/4625540/Hagicode/',
5354
targetPlatform: 'steam',
5455
}],
@@ -131,6 +132,7 @@ describe('docs promote banner source', () => {
131132
zh: '游戏将于 2026-04-29 发售,立即前往 Steam 添加愿望单。',
132133
en: 'Coming April 29, 2026. Add to your Steam wishlist now!',
133134
},
135+
cta: { zh: '加入愿望单', en: 'Wishlist on Steam' },
134136
link: 'https://store.steampowered.com/app/4625540/Hagicode/',
135137
targetPlatform: 'steam',
136138
},
@@ -150,6 +152,7 @@ describe('docs promote banner source', () => {
150152
id: 'main-game',
151153
title: 'Wishlist Now',
152154
description: 'Coming April 29, 2026. Add to your Steam wishlist now!',
155+
ctaLabel: 'Wishlist on Steam',
153156
link: 'https://store.steampowered.com/app/4625540/Hagicode/',
154157
platform: 'Steam',
155158
},
@@ -237,6 +240,31 @@ describe('docs promote banner source', () => {
237240
expect(promotions.map((promotion) => promotion.id)).toEqual(['valid']);
238241
});
239242

243+
it('resolves CTA labels from promotion content with shared fallback behavior', () => {
244+
const flags = {
245+
promotes: [
246+
{ id: 'localized', on: true },
247+
{ id: 'missing-locale', on: true },
248+
{ id: 'malformed-cta', on: true },
249+
{ id: 'legacy', on: true },
250+
],
251+
};
252+
const content = {
253+
contents: [
254+
{ id: 'localized', title: { zh: '中文标题', en: 'Localized' }, description: { zh: '中文描述', en: 'English copy' }, cta: { zh: '查看优惠', en: 'View Offer' }, link: 'https://example.invalid/localized' },
255+
{ id: 'missing-locale', title: { zh: '中文标题', en: 'Missing locale' }, description: { zh: '中文描述', en: 'Fallback copy' }, cta: { zh: '中文按钮' } as Record<string, string>, link: 'https://example.invalid/missing-locale' },
256+
{ id: 'malformed-cta', title: { zh: '中文标题', en: 'Malformed' }, description: { zh: '中文描述', en: 'Malformed copy' }, cta: { zh: '', en: ' ' }, link: 'https://example.invalid/malformed-cta' },
257+
{ id: 'legacy', title: { zh: '中文标题', en: 'Legacy' }, description: { zh: '中文描述', en: 'Legacy copy' }, link: 'https://example.invalid/legacy' },
258+
],
259+
};
260+
261+
const englishPromotions = normalizeActivePromotions(flags, content, 'en-US');
262+
const chinesePromotions = normalizeActivePromotions(flags, content, 'zh-CN');
263+
264+
expect(englishPromotions.map((promotion) => promotion.ctaLabel)).toEqual(['View Offer', '中文按钮', 'GO', 'GO']);
265+
expect(chinesePromotions.map((promotion) => promotion.ctaLabel)).toEqual(['查看优惠', '中文按钮', '立即前往', '立即前往']);
266+
});
267+
240268
it('returns a hidden-state empty list when promote payloads are invalid', async () => {
241269
const fetchMock = vi.fn(async (input: RequestInfo | URL) => {
242270
const url = input.toString();
@@ -322,6 +350,7 @@ describe('docs promote banner source', () => {
322350
zh: '游戏将于 2026-04-29 发售,立即前往 Steam 添加愿望单。',
323351
en: 'Coming April 29, 2026. Add to your Steam wishlist now!',
324352
},
353+
cta: { zh: '加入愿望单', en: 'Wishlist on Steam' },
325354
link: 'https://store.steampowered.com/app/4625540/Hagicode/',
326355
targetPlatform: 'steam',
327356
}],
@@ -338,6 +367,7 @@ describe('docs promote banner source', () => {
338367
id: 'main-game',
339368
title: 'Wishlist Now',
340369
description: 'Coming April 29, 2026. Add to your Steam wishlist now!',
370+
ctaLabel: 'Wishlist on Steam',
341371
link: 'https://store.steampowered.com/app/4625540/Hagicode/',
342372
platform: 'Steam',
343373
},
@@ -385,6 +415,7 @@ function createScheduleFetch(promotions: Array<{
385415
id: promotion.id,
386416
title: { zh: promotion.titleEn, en: promotion.titleEn },
387417
description: { zh: promotion.titleEn, en: promotion.titleEn },
418+
cta: { zh: `打开 ${promotion.id}`, en: `Open ${promotion.id}` },
388419
link: `https://example.invalid/${promotion.id}`,
389420
targetPlatform: 'steam',
390421
})),

src/lib/docs-promote-banner.ts

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ interface PromoteContentRecord {
3434
id: string;
3535
title: Record<string, string>;
3636
description: Record<string, string>;
37+
cta?: Record<string, string>;
3738
link: string;
3839
targetPlatform?: string;
3940
}
@@ -58,6 +59,7 @@ export interface ActivePromotion {
5859
id: string;
5960
title: string;
6061
description: string;
62+
ctaLabel: string;
6163
link: string;
6264
platform: string | null;
6365
}
@@ -85,12 +87,19 @@ function isNonEmptyString(value: unknown): value is string {
8587
return typeof value === 'string' && value.trim().length > 0;
8688
}
8789

88-
function isLocalizedStringMap(value: unknown): value is Record<string, string> {
90+
function sanitizeLocalizedStringMap(value: unknown): Record<string, string> | null {
8991
if (!isRecord(value)) {
90-
return false;
92+
return null;
93+
}
94+
95+
const entries: Array<[string, string]> = [];
96+
for (const [key, entryValue] of Object.entries(value)) {
97+
if (isNonEmptyString(key) && isNonEmptyString(entryValue)) {
98+
entries.push([key.trim(), entryValue.trim()]);
99+
}
91100
}
92101

93-
return Object.values(value).every(isNonEmptyString);
102+
return entries.length > 0 ? Object.fromEntries(entries) : null;
94103
}
95104

96105
function parseCatalogEntries(payload: unknown): IndexCatalogEntry[] {
@@ -178,17 +187,23 @@ function parsePromoteContentDocument(payload: unknown): PromoteContentDocument {
178187
if (
179188
!isRecord(record) ||
180189
!isNonEmptyString(record.id) ||
181-
!isLocalizedStringMap(record.title) ||
182-
!isLocalizedStringMap(record.description) ||
183190
!isNonEmptyString(record.link)
184191
) {
185192
return [];
186193
}
187194

195+
const title = sanitizeLocalizedStringMap(record.title);
196+
const description = sanitizeLocalizedStringMap(record.description);
197+
const cta = sanitizeLocalizedStringMap(record.cta);
198+
if (!title || !description) {
199+
return [];
200+
}
201+
188202
return [{
189203
id: record.id,
190-
title: record.title,
191-
description: record.description,
204+
title,
205+
description,
206+
cta: cta ?? undefined,
192207
link: record.link,
193208
targetPlatform: isNonEmptyString(record.targetPlatform) ? record.targetPlatform : undefined,
194209
}];
@@ -267,6 +282,17 @@ function pickLocalizedValue(
267282
return fallbackValue?.trim() ?? null;
268283
}
269284

285+
function resolveCtaLabel(value: Record<string, string> | undefined, locale: PromoteLocale): string {
286+
if (value) {
287+
const localized = pickLocalizedValue(value, locale);
288+
if (localized) {
289+
return localized;
290+
}
291+
}
292+
293+
return locale === 'zh' ? '立即前往' : 'GO';
294+
}
295+
270296
export async function resolvePromotionDocumentUrls(
271297
fetchImpl: FetchLike = fetch,
272298
): Promise<PromotionDocumentUrls> {
@@ -363,6 +389,7 @@ export function normalizeActivePromotions(
363389
id: promoteContent.id,
364390
title,
365391
description,
392+
ctaLabel: resolveCtaLabel(promoteContent.cta, promoteLocale),
366393
link: promoteContent.link,
367394
platform: localizePlatform(promoteContent.targetPlatform, promoteLocale),
368395
}];
@@ -382,7 +409,11 @@ export async function loadActivePromotions(
382409
}
383410
}
384411

385-
function setElementHidden(element: HTMLElement, hidden: boolean): void {
412+
function setElementHidden(element: HTMLElement | null, hidden: boolean): void {
413+
if (!element) {
414+
return;
415+
}
416+
386417
if (hidden) {
387418
element.setAttribute('hidden', '');
388419
element.style.setProperty('display', 'none');
@@ -677,7 +708,7 @@ export class DocsPromoteBannerController {
677708

678709
const cta = document.createElement('span');
679710
cta.className = 'docs-promote-banner__cta';
680-
cta.textContent = mapDocsLocaleToPromoteLocale(this.locale) === 'en' ? 'Open now' : '立即查看';
711+
cta.textContent = promotion.ctaLabel;
681712
actions.append(cta);
682713

683714
slide.append(copy, actions);

0 commit comments

Comments
 (0)