收口前端平台组件库能力
新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件 迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome 补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
This commit is contained in:
@@ -19,6 +19,7 @@ import type {
|
||||
import type {
|
||||
ConfirmWechatProfileRechargeOrderResponse,
|
||||
CreateProfileRechargeOrderResponse,
|
||||
ProfilePlayStatsResponse,
|
||||
ProfileReferralInviteCenterResponse,
|
||||
ProfileTaskCenterResponse,
|
||||
} from '../../../packages/shared/src/contracts/runtime';
|
||||
@@ -777,6 +778,8 @@ function ProfileHomeViewHarness({
|
||||
userOverrides = {},
|
||||
activeTab = 'profile',
|
||||
profileTaskRefreshKey = 0,
|
||||
profilePlayStats = null,
|
||||
isProfilePlayStatsOpen = false,
|
||||
}: {
|
||||
onRechargeSuccess?: () => void | Promise<void>;
|
||||
profileDashboardOverrides?: Partial<
|
||||
@@ -785,6 +788,8 @@ function ProfileHomeViewHarness({
|
||||
userOverrides?: Partial<AuthUser>;
|
||||
activeTab?: RpgEntryHomeViewProps['activeTab'];
|
||||
profileTaskRefreshKey?: number;
|
||||
profilePlayStats?: ProfilePlayStatsResponse | null;
|
||||
isProfilePlayStatsOpen?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<AuthUiContext.Provider
|
||||
@@ -837,6 +842,8 @@ function ProfileHomeViewHarness({
|
||||
isLoadingPlatform={false}
|
||||
isLoadingDashboard={false}
|
||||
isResumingSaveWorldKey={null}
|
||||
profilePlayStats={profilePlayStats}
|
||||
isProfilePlayStatsOpen={isProfilePlayStatsOpen}
|
||||
platformError={null}
|
||||
dashboardError={null}
|
||||
onContinueGame={vi.fn()}
|
||||
@@ -860,6 +867,10 @@ function renderProfileView(
|
||||
> = {},
|
||||
userOverrides: Partial<AuthUser> = {},
|
||||
profileTaskRefreshKey = 0,
|
||||
profileStatsOptions: {
|
||||
profilePlayStats?: ProfilePlayStatsResponse | null;
|
||||
isProfilePlayStatsOpen?: boolean;
|
||||
} = {},
|
||||
) {
|
||||
return render(
|
||||
<ProfileHomeViewHarness
|
||||
@@ -867,6 +878,8 @@ function renderProfileView(
|
||||
profileDashboardOverrides={profileDashboardOverrides}
|
||||
userOverrides={userOverrides}
|
||||
profileTaskRefreshKey={profileTaskRefreshKey}
|
||||
profilePlayStats={profileStatsOptions.profilePlayStats}
|
||||
isProfilePlayStatsOpen={profileStatsOptions.isProfilePlayStatsOpen}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
@@ -1141,7 +1154,10 @@ afterEach(() => {
|
||||
configurable: true,
|
||||
value: undefined,
|
||||
});
|
||||
Reflect.deleteProperty(globalThis as Record<string, unknown>, 'BarcodeDetector');
|
||||
Reflect.deleteProperty(
|
||||
globalThis as Record<string, unknown>,
|
||||
'BarcodeDetector',
|
||||
);
|
||||
window.wx = undefined;
|
||||
document
|
||||
.querySelectorAll(
|
||||
@@ -1238,11 +1254,16 @@ test('opens wallet ledger modal from narrative coin card', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
renderProfileView();
|
||||
await user.click(
|
||||
screen.getByRole('button', { name: /泥点余额\s*0/u }),
|
||||
);
|
||||
await user.click(screen.getByRole('button', { name: /泥点余额\s*0/u }));
|
||||
|
||||
expect(await screen.findByText('泥点账单')).toBeTruthy();
|
||||
const ledgerModal = screen
|
||||
.getByText('泥点账单')
|
||||
.closest('.fixed') as HTMLElement;
|
||||
const balanceBadge = within(ledgerModal).getByText('29泥点');
|
||||
expect(balanceBadge.className).toContain('rounded-full');
|
||||
expect(balanceBadge.className).toContain('border-rose-100');
|
||||
expect(balanceBadge.className).toContain('bg-white/70');
|
||||
expect(mockGetRpgProfileWalletLedger).toHaveBeenCalledTimes(1);
|
||||
expect(screen.getByText('资产操作消耗')).toBeTruthy();
|
||||
expect(screen.getByText('-1')).toBeTruthy();
|
||||
@@ -1577,7 +1598,8 @@ test('profile recharge modal posts membership goods virtual payment params in mi
|
||||
);
|
||||
expect(requestId).toBeTruthy();
|
||||
const payParams = JSON.parse(
|
||||
new URL(`https://mini.test${navigateUrl}`).searchParams.get('payParams') ?? '{}',
|
||||
new URL(`https://mini.test${navigateUrl}`).searchParams.get('payParams') ??
|
||||
'{}',
|
||||
);
|
||||
const signData = JSON.parse(payParams.signData);
|
||||
expect(payParams.mode).toBe('short_series_goods');
|
||||
@@ -1654,9 +1676,7 @@ test('profile recharge modal releases submitting state and shows virtual payment
|
||||
expect(
|
||||
await screen.findByRole('dialog', { name: '支付未完成' }),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
screen.getByText(/requestVirtualPayment:fail sandbox/u),
|
||||
).toBeTruthy();
|
||||
expect(screen.getByText(/requestVirtualPayment:fail sandbox/u)).toBeTruthy();
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
within(screen.getByRole('button', { name: /60泥点/u })).getByText(
|
||||
@@ -2222,7 +2242,9 @@ test('profile recharge modal blocks tab navigation while virtual payment confirm
|
||||
hasPointsRecharged: false,
|
||||
},
|
||||
});
|
||||
mockWatchWechatRpgProfileRechargeOrder.mockReturnValueOnce(new Promise(() => undefined));
|
||||
mockWatchWechatRpgProfileRechargeOrder.mockReturnValueOnce(
|
||||
new Promise(() => undefined),
|
||||
);
|
||||
|
||||
renderProfileView();
|
||||
await openRechargeModal(user);
|
||||
@@ -2527,7 +2549,9 @@ test('profile daily task shortcut reflects task progress and claim updates', asy
|
||||
await waitFor(() => {
|
||||
expect(within(dailyTask).getByText('1 / 1')).toBeTruthy();
|
||||
});
|
||||
expect(dailyTask.querySelector('.platform-profile-daily-task-card__action')).toBeNull();
|
||||
expect(
|
||||
dailyTask.querySelector('.platform-profile-daily-task-card__action'),
|
||||
).toBeNull();
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /每日任务/u }));
|
||||
|
||||
@@ -2695,6 +2719,55 @@ test('profile total play time card always uses hours', async () => {
|
||||
await screen.findByText('1 / 1');
|
||||
});
|
||||
|
||||
test('profile played modal summary and work type use platform pill badges', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
renderProfileView(
|
||||
vi.fn(),
|
||||
{
|
||||
totalPlayTimeMs: 90 * 60 * 1000,
|
||||
playedWorldCount: 1,
|
||||
},
|
||||
{},
|
||||
0,
|
||||
{
|
||||
isProfilePlayStatsOpen: true,
|
||||
profilePlayStats: {
|
||||
totalPlayTimeMs: 90 * 60 * 1000,
|
||||
playedWorks: [
|
||||
{
|
||||
worldKey: 'custom:world-1',
|
||||
ownerUserId: 'user-1',
|
||||
profileId: 'world-1',
|
||||
worldType: 'CUSTOM',
|
||||
worldTitle: '潮雾列岛',
|
||||
worldSubtitle: '旧灯塔与失控航路',
|
||||
firstPlayedAt: '2026-04-18T12:00:00.000Z',
|
||||
lastPlayedAt: '2026-04-19T12:00:00.000Z',
|
||||
lastObservedPlayTimeMs: 30 * 60 * 1000,
|
||||
},
|
||||
],
|
||||
updatedAt: '2026-04-19T12:00:00.000Z',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /已玩游戏数量/u }));
|
||||
|
||||
const playedModal = screen
|
||||
.getByText('潮雾列岛')
|
||||
.closest('.fixed') as HTMLElement;
|
||||
const totalPlayTimeBadge = within(playedModal).getByText('1.5小时');
|
||||
expect(totalPlayTimeBadge.className).toContain('rounded-full');
|
||||
expect(totalPlayTimeBadge.className).toContain('border-rose-100');
|
||||
expect(totalPlayTimeBadge.className).toContain('bg-rose-50');
|
||||
|
||||
const workTypeBadge = within(playedModal).getByText('RPG');
|
||||
expect(workTypeBadge.className).toContain('rounded-full');
|
||||
expect(workTypeBadge.className).toContain('bg-rose-50');
|
||||
expect(workTypeBadge.className).toContain('text-[#ff4056]');
|
||||
});
|
||||
|
||||
test('profile played works card shows count unit', async () => {
|
||||
renderProfileView(vi.fn(), {
|
||||
playedWorldCount: 1,
|
||||
@@ -2744,9 +2817,13 @@ test('mobile profile page matches the reference layout sections', async () => {
|
||||
const profilePage = container.querySelector('.platform-profile-page');
|
||||
expect(profilePage).toBeTruthy();
|
||||
expect(profilePage?.classList.contains('platform-page-stage')).toBe(false);
|
||||
expect(profilePage?.querySelector('.platform-profile-scene-decor')).toBeTruthy();
|
||||
expect(
|
||||
profilePage?.querySelector('.platform-profile-scene-decor'),
|
||||
).toBeTruthy();
|
||||
expect(profilePage?.classList.contains('platform-profile-page')).toBe(true);
|
||||
expect(profilePage?.getAttribute('style') ?? '').not.toContain('overflow: hidden');
|
||||
expect(profilePage?.getAttribute('style') ?? '').not.toContain(
|
||||
'overflow: hidden',
|
||||
);
|
||||
|
||||
const topbar = container.querySelector('.platform-mobile-topbar');
|
||||
expect(topbar).toBeTruthy();
|
||||
@@ -2763,30 +2840,50 @@ test('mobile profile page matches the reference layout sections', async () => {
|
||||
).toBeNull();
|
||||
|
||||
const membershipCard = screen.getByRole('button', { name: '查看权益' });
|
||||
expect(membershipCard.className).toContain('platform-profile-membership-card');
|
||||
expect(
|
||||
within(membershipCard).getByText('普通用户').className,
|
||||
).toContain('platform-profile-membership-card__title');
|
||||
expect(membershipCard.className).toContain(
|
||||
'platform-profile-membership-card',
|
||||
);
|
||||
expect(within(membershipCard).getByText('普通用户').className).toContain(
|
||||
'platform-profile-membership-card__title',
|
||||
);
|
||||
expect(within(membershipCard).getByText('普通用户')).toBeTruthy();
|
||||
expect(within(membershipCard).getByText('升级会员,享专属特权与福利')).toBeTruthy();
|
||||
expect(
|
||||
within(membershipCard).getByText('升级会员,享专属特权与福利'),
|
||||
).toBeTruthy();
|
||||
|
||||
const statPanel = screen.getByRole('region', { name: '我的数据' });
|
||||
expect(statPanel.className).toContain('platform-profile-stats-panel');
|
||||
expect(statPanel.querySelector('.platform-profile-stats-grid')).toBeTruthy();
|
||||
expect(within(statPanel).getByRole('button', { name: /泥点余额\s*70/u })).toBeTruthy();
|
||||
expect(within(statPanel).getByRole('button', { name: /累计游戏时长\s*0小时/u })).toBeTruthy();
|
||||
expect(within(statPanel).getByRole('button', { name: /已玩游戏数量\s*0个/u })).toBeTruthy();
|
||||
expect(
|
||||
within(statPanel).getByRole('button', { name: /泥点余额\s*70/u }),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
within(statPanel).getByRole('button', { name: /累计游戏时长\s*0小时/u }),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
within(statPanel).getByRole('button', { name: /已玩游戏数量\s*0个/u }),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
within(statPanel).getByRole('button', { name: /泥点余额\s*70/u }).className,
|
||||
).toContain('platform-profile-stat-card');
|
||||
expect(statPanel.querySelectorAll('.platform-profile-stat-card__icon')).toHaveLength(3);
|
||||
expect(
|
||||
statPanel.querySelectorAll('.platform-profile-stat-card__icon'),
|
||||
).toHaveLength(3);
|
||||
|
||||
const dailyTask = screen.getByRole('button', { name: /每日任务/u });
|
||||
expect(dailyTask.className).toContain('platform-profile-daily-task-card');
|
||||
expect(dailyTask.querySelector('.platform-profile-daily-task-card__title')).toBeTruthy();
|
||||
expect(dailyTask.querySelector('.platform-profile-daily-task-card__desc')).toBeTruthy();
|
||||
expect(dailyTask.querySelector('.platform-profile-daily-task-card__progress')).toBeTruthy();
|
||||
expect(dailyTask.querySelector('.platform-profile-daily-task-card__action')).toBeNull();
|
||||
expect(
|
||||
dailyTask.querySelector('.platform-profile-daily-task-card__title'),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
dailyTask.querySelector('.platform-profile-daily-task-card__desc'),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
dailyTask.querySelector('.platform-profile-daily-task-card__progress'),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
dailyTask.querySelector('.platform-profile-daily-task-card__action'),
|
||||
).toBeNull();
|
||||
expect(dailyTask.textContent).not.toContain('去完成');
|
||||
expect(dailyTask.textContent).toContain('完成任务可领取 10 泥点');
|
||||
expect(await within(dailyTask).findByText('1 / 1')).toBeTruthy();
|
||||
@@ -2804,28 +2901,21 @@ test('mobile profile page matches the reference layout sections', async () => {
|
||||
?.classList.contains('platform-profile-shortcut-grid'),
|
||||
).toBe(true);
|
||||
expect(
|
||||
shortcutRegion
|
||||
.querySelector('.platform-profile-shortcut-grid')
|
||||
?.className,
|
||||
shortcutRegion.querySelector('.platform-profile-shortcut-grid')?.className,
|
||||
).toContain('!grid-cols-4');
|
||||
expect(
|
||||
shortcutRegion
|
||||
.querySelector('.platform-profile-shortcut-grid')
|
||||
?.className,
|
||||
shortcutRegion.querySelector('.platform-profile-shortcut-grid')?.className,
|
||||
).toContain('w-full');
|
||||
for (const shortcutButton of shortcutRegion.querySelectorAll(
|
||||
'.platform-profile-shortcut-button',
|
||||
)) {
|
||||
expect(shortcutButton.className).toContain('w-full');
|
||||
}
|
||||
for (const label of [
|
||||
'泥点充值',
|
||||
'兑换码',
|
||||
'玩家社区',
|
||||
'反馈与建议',
|
||||
]) {
|
||||
for (const label of ['泥点充值', '兑换码', '玩家社区', '反馈与建议']) {
|
||||
expect(
|
||||
within(shortcutRegion).getByRole('button', { name: new RegExp(label, 'u') }),
|
||||
within(shortcutRegion).getByRole('button', {
|
||||
name: new RegExp(label, 'u'),
|
||||
}),
|
||||
).toBeTruthy();
|
||||
}
|
||||
expect(
|
||||
@@ -2840,10 +2930,18 @@ test('mobile profile page matches the reference layout sections', async () => {
|
||||
).toBeNull();
|
||||
|
||||
const settingsRegion = screen.getByRole('region', { name: '设置入口' });
|
||||
expect(within(settingsRegion).getByRole('button', { name: /通用设置/u })).toBeTruthy();
|
||||
expect(within(settingsRegion).queryByRole('button', { name: /主题设置/u })).toBeNull();
|
||||
expect(within(settingsRegion).queryByRole('button', { name: /账号与安全/u })).toBeNull();
|
||||
expect(settingsRegion.querySelectorAll('.platform-profile-settings-row')).toHaveLength(1);
|
||||
expect(
|
||||
within(settingsRegion).getByRole('button', { name: /通用设置/u }),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
within(settingsRegion).queryByRole('button', { name: /主题设置/u }),
|
||||
).toBeNull();
|
||||
expect(
|
||||
within(settingsRegion).queryByRole('button', { name: /账号与安全/u }),
|
||||
).toBeNull();
|
||||
expect(
|
||||
settingsRegion.querySelectorAll('.platform-profile-settings-row'),
|
||||
).toHaveLength(1);
|
||||
expect(
|
||||
within(settingsRegion).queryByRole('button', { name: /存档/u }),
|
||||
).toBeNull();
|
||||
@@ -2852,9 +2950,15 @@ test('mobile profile page matches the reference layout sections', async () => {
|
||||
|
||||
const profileHeader = profilePage?.querySelector('.platform-profile-header');
|
||||
expect(profileHeader).toBeTruthy();
|
||||
expect(profileHeader?.querySelector('.platform-profile-header__identity-row')).toBeTruthy();
|
||||
expect(profileHeader?.querySelector('.platform-profile-header__name')).toBeTruthy();
|
||||
expect(profileHeader?.querySelector('.platform-profile-header__code')).toBeTruthy();
|
||||
expect(
|
||||
profileHeader?.querySelector('.platform-profile-header__identity-row'),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
profileHeader?.querySelector('.platform-profile-header__name'),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
profileHeader?.querySelector('.platform-profile-header__code'),
|
||||
).toBeTruthy();
|
||||
|
||||
const legalRegion = screen.getByRole('region', { name: '法律信息' });
|
||||
expect(legalRegion.className).toContain('platform-profile-legal-strip');
|
||||
@@ -2863,7 +2967,9 @@ test('mobile profile page matches the reference layout sections', async () => {
|
||||
expect(legalRegion.textContent).toContain('免责声明');
|
||||
expect(legalRegion.textContent).toContain(ICP_RECORD_NUMBER);
|
||||
expect(legalRegion.textContent).toContain('2026025677');
|
||||
expect(legalRegion.querySelector('.platform-profile-legal-strip__link')).toBeTruthy();
|
||||
expect(
|
||||
legalRegion.querySelector('.platform-profile-legal-strip__link'),
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
test('profile scan action opens camera scanner instead of recharge panel', async () => {
|
||||
@@ -2989,10 +3095,7 @@ test('profile community shortcut shows reward subtitle and invited users', async
|
||||
});
|
||||
|
||||
test('profile page hides legacy redeem invite secondary shortcut for fresh accounts', async () => {
|
||||
renderProfileView(
|
||||
vi.fn(),
|
||||
{},
|
||||
);
|
||||
renderProfileView(vi.fn(), {});
|
||||
|
||||
const communityButton = screen.getByRole('button', { name: /玩家社区/u });
|
||||
|
||||
@@ -3080,10 +3183,7 @@ test('profile redeem invite query modal submits code after login', async () => {
|
||||
const onRechargeSuccess = vi.fn();
|
||||
window.history.replaceState(null, '', '/?inviteCode=spring-2026');
|
||||
|
||||
renderProfileView(
|
||||
onRechargeSuccess,
|
||||
{},
|
||||
);
|
||||
renderProfileView(onRechargeSuccess, {});
|
||||
|
||||
expect(await screen.findByLabelText('邀请码')).toBeTruthy();
|
||||
await user.click(screen.getByRole('button', { name: '提交' }));
|
||||
@@ -3105,9 +3205,7 @@ test('profile task center reloads when refresh key changes', async () => {
|
||||
expect(mockGetRpgProfileTasks).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
rerender(
|
||||
<ProfileHomeViewHarness profileTaskRefreshKey={1} />,
|
||||
);
|
||||
rerender(<ProfileHomeViewHarness profileTaskRefreshKey={1} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockGetRpgProfileTasks).toHaveBeenCalledTimes(2);
|
||||
@@ -3152,12 +3250,20 @@ test('profile page shows legal entries and hides archive shortcuts', async () =>
|
||||
const dailyTask = screen.getByRole('button', { name: /每日任务/u });
|
||||
expect(dailyTask).toBeTruthy();
|
||||
expect(dailyTask.textContent).toContain('完成任务可领取 10 泥点');
|
||||
expect(dailyTask.querySelector('.platform-profile-daily-task-card__action')).toBeNull();
|
||||
expect(
|
||||
dailyTask.querySelector('.platform-profile-daily-task-card__action'),
|
||||
).toBeNull();
|
||||
|
||||
const settingsRegion = screen.getByRole('region', { name: '设置入口' });
|
||||
expect(within(settingsRegion).getByRole('button', { name: /通用设置/u })).toBeTruthy();
|
||||
expect(within(settingsRegion).queryByRole('button', { name: /主题设置/u })).toBeNull();
|
||||
expect(within(settingsRegion).queryByRole('button', { name: /账号与安全/u })).toBeNull();
|
||||
expect(
|
||||
within(settingsRegion).getByRole('button', { name: /通用设置/u }),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
within(settingsRegion).queryByRole('button', { name: /主题设置/u }),
|
||||
).toBeNull();
|
||||
expect(
|
||||
within(settingsRegion).queryByRole('button', { name: /账号与安全/u }),
|
||||
).toBeNull();
|
||||
expect(
|
||||
within(settingsRegion).queryByRole('button', { name: /存档/u }),
|
||||
).toBeNull();
|
||||
@@ -3737,10 +3843,15 @@ test('logged out recommend runtime keeps detail callback idle', async () => {
|
||||
|
||||
test('logged out desktop recommend page renders runtime directly', () => {
|
||||
mockDesktopLayout();
|
||||
renderLoggedOutHomeView(vi.fn(), {
|
||||
latestEntries: [puzzlePublicEntry],
|
||||
activeRecommendEntryKey: 'puzzle:user-2:puzzle-profile-public-1',
|
||||
}, 'home', true);
|
||||
renderLoggedOutHomeView(
|
||||
vi.fn(),
|
||||
{
|
||||
latestEntries: [puzzlePublicEntry],
|
||||
activeRecommendEntryKey: 'puzzle:user-2:puzzle-profile-public-1',
|
||||
},
|
||||
'home',
|
||||
true,
|
||||
);
|
||||
|
||||
expect(document.querySelector('.platform-recommend-cover-only')).toBeNull();
|
||||
expect(screen.queryByTestId('recommend-runtime')).toBeNull();
|
||||
@@ -3755,10 +3866,14 @@ test('logged out recommend page can enter runtime without login gate', () => {
|
||||
latestEntries: [puzzlePublicEntry],
|
||||
activeRecommendEntryKey: 'puzzle:user-2:puzzle-profile-public-1',
|
||||
onOpenGalleryDetail,
|
||||
recommendRuntimeContent: <div data-testid="recommend-runtime">运行内容</div>,
|
||||
recommendRuntimeContent: (
|
||||
<div data-testid="recommend-runtime">运行内容</div>
|
||||
),
|
||||
});
|
||||
|
||||
expect(screen.queryByRole('button', { name: /登录后游玩 奇幻拼图/u })).toBeNull();
|
||||
expect(
|
||||
screen.queryByRole('button', { name: /登录后游玩 奇幻拼图/u }),
|
||||
).toBeNull();
|
||||
expect(screen.getByTestId('recommend-runtime')).toBeTruthy();
|
||||
expect(openLoginModal).not.toHaveBeenCalled();
|
||||
expect(onOpenGalleryDetail).not.toHaveBeenCalled();
|
||||
@@ -3767,7 +3882,8 @@ test('logged out recommend page can enter runtime without login gate', () => {
|
||||
test('mobile recommend meta matches active jump hop runtime entry', () => {
|
||||
renderLoggedOutHomeView(vi.fn(), {
|
||||
latestEntries: [puzzlePublicEntry, jumpHopPublicEntry],
|
||||
activeRecommendEntryKey: 'jump-hop:jump-hop-user-1:jump-hop-profile-public-1',
|
||||
activeRecommendEntryKey:
|
||||
'jump-hop:jump-hop-user-1:jump-hop-profile-public-1',
|
||||
recommendRuntimeContent: (
|
||||
<div data-testid="recommend-runtime">跳一跳运行内容</div>
|
||||
),
|
||||
@@ -3932,7 +4048,9 @@ test('logged out mobile recommend page renders runtime instead of cover', () =>
|
||||
document.querySelector('.platform-public-work-card__cover'),
|
||||
).toBeNull();
|
||||
expect(screen.getAllByText('奇幻拼图').length).toBeGreaterThan(0);
|
||||
expect(screen.queryByRole('button', { name: /登录后游玩 奇幻拼图/u })).toBeNull();
|
||||
expect(
|
||||
screen.queryByRole('button', { name: /登录后游玩 奇幻拼图/u }),
|
||||
).toBeNull();
|
||||
expect(onOpenGalleryDetail).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -4013,7 +4131,9 @@ test('mobile recommend preloads every fetched work cover', () => {
|
||||
);
|
||||
expect(preloadedSrcs).not.toContain('/generated-recommend/current.png');
|
||||
return waitFor(() => {
|
||||
expect(preloadedSrcs).toContain('https://signed.example.com/current-cover.png');
|
||||
expect(preloadedSrcs).toContain(
|
||||
'https://signed.example.com/current-cover.png',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4037,7 +4157,9 @@ test('mobile recommend runtime cover keeps the labeled work card visual', () =>
|
||||
|
||||
expect(coverImage?.getAttribute('src')).toBe('card-cover-1.png');
|
||||
expect(coverImage?.getAttribute('src')).not.toBe('card-cover-fallback.png');
|
||||
expect(cover?.querySelector('.platform-recommend-runtime-preview')).toBeTruthy();
|
||||
expect(
|
||||
cover?.querySelector('.platform-recommend-runtime-preview'),
|
||||
).toBeTruthy();
|
||||
expect(cover?.textContent).toContain('拼图');
|
||||
expect(cover?.textContent).toContain('轮播拼图');
|
||||
});
|
||||
@@ -4539,7 +4661,9 @@ test('logged in recommend runtime preloads adjacent work previews and drag switc
|
||||
expect(onLikeRecommendEntry).toHaveBeenCalledWith(firstEntry);
|
||||
expect(onShareRecommendEntry).toHaveBeenCalledWith(firstEntry);
|
||||
expect(onRemixRecommendEntry).toHaveBeenCalledWith(firstEntry);
|
||||
expect(activeRecommendCard.getByRole('button', { name: '分享' })).toBeTruthy();
|
||||
expect(
|
||||
activeRecommendCard.getByRole('button', { name: '分享' }),
|
||||
).toBeTruthy();
|
||||
|
||||
act(() => {
|
||||
dispatchPointerEvent(meta, 'pointerdown', { pointerId: 1, clientY: 300 });
|
||||
|
||||
Reference in New Issue
Block a user