fix: settle puzzle failures and profile tasks

This commit is contained in:
kdletters
2026-05-26 22:02:58 +08:00
parent 4001ee0a5c
commit 17a184b0a7
14 changed files with 436 additions and 81 deletions

View File

@@ -702,14 +702,22 @@ function mockNarrowMobileLayout() {
});
}
function renderProfileView(
function ProfileHomeViewHarness({
onRechargeSuccess = vi.fn(),
profileDashboardOverrides: Partial<
profileDashboardOverrides = {},
userOverrides = {},
activeTab = 'profile',
profileTaskRefreshKey = 0,
}: {
onRechargeSuccess?: () => void | Promise<void>;
profileDashboardOverrides?: Partial<
NonNullable<RpgEntryHomeViewProps['profileDashboard']>
> = {},
userOverrides: Partial<AuthUser> = {},
) {
return render(
>;
userOverrides?: Partial<AuthUser>;
activeTab?: RpgEntryHomeViewProps['activeTab'];
profileTaskRefreshKey?: number;
}) {
return (
<AuthUiContext.Provider
value={{
user: {
@@ -742,7 +750,7 @@ function renderProfileView(
}}
>
<RpgEntryHomeView
activeTab="profile"
activeTab={activeTab}
onTabChange={vi.fn()}
hasSavedGame={false}
savedSnapshot={null}
@@ -772,8 +780,27 @@ function renderProfileView(
onOpenLibraryDetail={vi.fn()}
onSearchPublicCode={vi.fn()}
onRechargeSuccess={onRechargeSuccess}
profileTaskRefreshKey={profileTaskRefreshKey}
/>
</AuthUiContext.Provider>,
</AuthUiContext.Provider>
);
}
function renderProfileView(
onRechargeSuccess = vi.fn(),
profileDashboardOverrides: Partial<
NonNullable<RpgEntryHomeViewProps['profileDashboard']>
> = {},
userOverrides: Partial<AuthUser> = {},
profileTaskRefreshKey = 0,
) {
return render(
<ProfileHomeViewHarness
onRechargeSuccess={onRechargeSuccess}
profileDashboardOverrides={profileDashboardOverrides}
userOverrides={userOverrides}
profileTaskRefreshKey={profileTaskRefreshKey}
/>,
);
}
@@ -2026,7 +2053,7 @@ test('mobile profile page matches the reference layout sections', async () => {
).toBeTruthy();
expect(
shortcutRegion.querySelectorAll('.platform-profile-shortcut-button'),
).toHaveLength(5);
).toHaveLength(4);
expect(
shortcutRegion
.querySelector('.platform-profile-shortcut-grid')
@@ -2034,7 +2061,6 @@ test('mobile profile page matches the reference layout sections', async () => {
).toBe(true);
for (const label of [
'泥点充值',
'邀请好友',
'兑换码',
'玩家社区',
'反馈与建议',
@@ -2172,28 +2198,25 @@ test('wallet ledger modal shows empty and error states', async () => {
expect(screen.getByText('重新加载')).toBeTruthy();
});
test('profile invite shortcut shows reward subtitle and invited users', async () => {
test('profile community shortcut shows reward subtitle and invited users', async () => {
const user = userEvent.setup();
renderProfileView(vi.fn(), {}, { createdAt: buildFreshProfileCreatedAt() });
const inviteButton = screen.getByRole('button', { name: //u });
expect(within(inviteButton).getByText('双方得 30 泥点')).toBeTruthy();
expect(screen.queryByRole('button', { name: //u })).toBeNull();
const communityButton = screen.getByRole('button', { name: //u });
expect(within(communityButton).getByText('交流心得 领取福利')).toBeTruthy();
await user.click(inviteButton);
await user.click(communityButton);
expect(mockGetRpgProfileReferralInviteCenter).toHaveBeenCalledTimes(1);
expect(
await screen.findByText('邀请一个用户注册双方都可以获得30泥点。'),
).toBeTruthy();
expect(screen.getByText('每日最多获得十次邀请奖励。')).toBeTruthy();
expect(screen.getByText('成功邀请')).toBeTruthy();
expect(screen.getByText('被邀请玩家')).toBeTruthy();
expect(screen.queryByText('已奖')).toBeNull();
expect(screen.queryByText('今日')).toBeNull();
expect(screen.getByAltText('玩家社区微信群二维码')).toBeTruthy();
expect(screen.getByAltText('玩家社区 QQ 群二维码')).toBeTruthy();
expect(screen.getByText('微信群')).toBeTruthy();
expect(screen.getByText('QQ群')).toBeTruthy();
expect(screen.queryByText('成功邀请')).toBeNull();
expect(screen.queryByText('被邀请玩家')).toBeNull();
});
test('profile page hides legacy redeem invite secondary shortcut for fresh accounts', async () => {
@@ -2203,50 +2226,55 @@ test('profile page hides legacy redeem invite secondary shortcut for fresh accou
{ createdAt: buildFreshProfileCreatedAt() },
);
const inviteButton = screen.getByRole('button', { name: //u });
const communityButton = screen.getByRole('button', { name: //u });
await waitFor(() => {
expect(mockGetRpgProfileReferralInviteCenter).toHaveBeenCalledTimes(1);
});
expect(inviteButton).toBeTruthy();
expect(screen.queryByRole('button', { name: //u })).toBeNull();
expect(communityButton).toBeTruthy();
expect(screen.queryByRole('region', { name: '次级入口' })).toBeNull();
expect(screen.queryByRole('button', { name: //u })).toBeNull();
});
test('profile redeem invite shortcut hides after redeemed or one day old', async () => {
const user = userEvent.setup();
mockGetRpgProfileReferralInviteCenter.mockResolvedValueOnce(
mockBuildReferralCenter({
invitedUsers: [],
hasRedeemedCode: true,
boundInviterUserId: 'user-2',
boundAt: '2026-05-01T08:00:00Z',
}),
);
const { unmount } = renderProfileView();
await user.click(screen.getByRole('button', { name: //u }));
await screen.findByText('成功邀请');
const firstShortcutRegion = screen.getByRole('region', { name: '常用功能' });
expect(
within(firstShortcutRegion).queryByRole('button', { name: //u }),
).toBeNull();
expect(
within(firstShortcutRegion).queryByRole('button', { name: //u }),
).toBeNull();
await screen.findByText('1 / 1');
await waitFor(() => {
expect(mockGetRpgProfileTasks).toHaveBeenCalledTimes(1);
});
await act(async () => {
await Promise.resolve();
});
unmount();
renderProfileView(vi.fn(), {}, { createdAt: '2026-04-01T00:00:00.000Z' });
const expiredShortcutRegion = screen.getByRole('region', {
name: '常用功能',
});
expect(
within(expiredShortcutRegion).queryByRole('button', {
name: //u,
}),
).toBeNull();
expect(
within(expiredShortcutRegion).queryByRole('button', {
name: //u,
}),
).toBeNull();
await screen.findByText('1 / 1');
await waitFor(() => {
expect(mockGetRpgProfileTasks).toHaveBeenCalledTimes(2);
});
await act(async () => {
await Promise.resolve();
});
});
test('invite query opens login modal for logged out users', async () => {
@@ -2303,6 +2331,22 @@ test('profile redeem invite query modal submits code after login', async () => {
expect(screen.queryByRole('region', { name: '次级入口' })).toBeNull();
});
test('profile task center reloads when refresh key changes', async () => {
const { rerender } = renderProfileView();
await waitFor(() => {
expect(mockGetRpgProfileTasks).toHaveBeenCalledTimes(1);
});
rerender(
<ProfileHomeViewHarness profileTaskRefreshKey={1} />,
);
await waitFor(() => {
expect(mockGetRpgProfileTasks).toHaveBeenCalledTimes(2);
});
});
test('opens reward code modal from profile action on mobile', async () => {
const user = userEvent.setup();
@@ -2330,8 +2374,8 @@ test('profile page shows legal entries and hides archive shortcuts', async () =>
?.classList.contains('platform-profile-shortcut-grid'),
).toBe(true);
expect(
within(shortcutRegion).getByRole('button', { name: //u }),
).toBeTruthy();
within(shortcutRegion).queryByRole('button', { name: //u }),
).toBeNull();
expect(
within(shortcutRegion).getByRole('button', { name: //u }),
).toBeTruthy();