Add skill for gameplay entry type workflows

This commit is contained in:
2026-05-04 02:32:38 +08:00
parent 49aad7311c
commit 34aecdddf1
77 changed files with 5997 additions and 110 deletions

View File

@@ -9,7 +9,10 @@ import type {
AuthUser,
PublicUserSummary,
} from '../../../packages/shared/src/contracts/auth';
import type { ProfileReferralInviteCenterResponse } from '../../../packages/shared/src/contracts/runtime';
import type {
ProfileReferralInviteCenterResponse,
ProfileTaskCenterResponse,
} from '../../../packages/shared/src/contracts/runtime';
import { AuthUiContext } from '../auth/AuthUiContext';
import {
RpgEntryHomeView,
@@ -19,7 +22,10 @@ import type { PlatformPublicGalleryCard } from './rpgEntryWorldPresentation';
const {
mockBuildReferralCenter,
mockBuildTaskCenter,
mockClaimRpgProfileTaskReward,
mockGetRpgProfileReferralInviteCenter,
mockGetRpgProfileTasks,
mockGetRpgProfileWalletLedger,
mockRedeemRpgProfileReferralInviteCode,
} = vi.hoisted(() => {
@@ -47,12 +53,73 @@ const {
updatedAt: '2026-05-01T08:00:00Z',
...overrides,
});
const buildTaskCenter = (
overrides: Partial<ProfileTaskCenterResponse> = {},
): ProfileTaskCenterResponse => ({
dayKey: 20260503,
walletBalance: 0,
tasks: [
{
taskId: 'daily_login',
title: '每日登录',
description: '',
eventKey: 'profile.login.daily',
cycle: 'daily',
threshold: 1,
progressCount: 1,
rewardPoints: 10,
status: 'claimable',
dayKey: 20260503,
claimedAt: null,
updatedAt: '2026-05-03T08:00:00Z',
},
],
updatedAt: '2026-05-03T08:00:00Z',
...overrides,
});
const buildClaimedTaskCenter = () =>
buildTaskCenter({
walletBalance: 10,
tasks: [
{
taskId: 'daily_login',
title: '每日登录',
description: '',
eventKey: 'profile.login.daily',
cycle: 'daily',
threshold: 1,
progressCount: 1,
rewardPoints: 10,
status: 'claimed',
dayKey: 20260503,
claimedAt: '2026-05-03T08:01:00Z',
updatedAt: '2026-05-03T08:01:00Z',
},
],
updatedAt: '2026-05-03T08:01:00Z',
});
return {
mockBuildReferralCenter: buildReferralCenter,
mockBuildTaskCenter: buildTaskCenter,
mockGetRpgProfileReferralInviteCenter: vi.fn(async () =>
buildReferralCenter(),
),
mockGetRpgProfileTasks: vi.fn(async () => buildTaskCenter()),
mockClaimRpgProfileTaskReward: vi.fn(async () => ({
taskId: 'daily_login',
dayKey: 20260503,
rewardPoints: 10,
walletBalance: 10,
ledgerEntry: {
id: 'ledger-daily-login',
amountDelta: 10,
balanceAfter: 10,
sourceType: 'daily_task_reward',
createdAt: '2026-05-03T08:01:00Z',
},
center: buildClaimedTaskCenter(),
})),
mockRedeemRpgProfileReferralInviteCode: vi.fn(async () => ({
center: buildReferralCenter({
invitedUsers: [],
@@ -131,7 +198,9 @@ mockUpdateAuthProfile.mockResolvedValue({
vi.mock('../../services/rpg-entry/rpgProfileClient', () => ({
getRpgProfileReferralInviteCenter: mockGetRpgProfileReferralInviteCenter,
getRpgProfileTasks: mockGetRpgProfileTasks,
getRpgProfileWalletLedger: mockGetRpgProfileWalletLedger,
claimRpgProfileTaskReward: mockClaimRpgProfileTaskReward,
redeemRpgProfileReferralInviteCode: mockRedeemRpgProfileReferralInviteCode,
getRpgProfileRechargeCenter: vi.fn(async () => ({
walletBalance: 0,
@@ -558,6 +627,40 @@ afterEach(() => {
mockGetRpgProfileReferralInviteCenter.mockResolvedValue(
mockBuildReferralCenter(),
);
mockGetRpgProfileTasks.mockResolvedValue(mockBuildTaskCenter());
mockClaimRpgProfileTaskReward.mockResolvedValue({
taskId: 'daily_login',
dayKey: 20260503,
rewardPoints: 10,
walletBalance: 10,
ledgerEntry: {
id: 'ledger-daily-login',
amountDelta: 10,
balanceAfter: 10,
sourceType: 'daily_task_reward',
createdAt: '2026-05-03T08:01:00Z',
},
center: mockBuildTaskCenter({
walletBalance: 10,
tasks: [
{
taskId: 'daily_login',
title: '每日登录',
description: '',
eventKey: 'profile.login.daily',
cycle: 'daily',
threshold: 1,
progressCount: 1,
rewardPoints: 10,
status: 'claimed',
dayKey: 20260503,
claimedAt: '2026-05-03T08:01:00Z',
updatedAt: '2026-05-03T08:01:00Z',
},
],
updatedAt: '2026-05-03T08:01:00Z',
}),
});
mockUpdateAuthProfile.mockResolvedValue({
id: 'user-1',
publicUserCode: '100001',
@@ -605,6 +708,31 @@ test('opens wallet ledger modal from narrative coin card', async () => {
expect(screen.getByText('+30')).toBeTruthy();
});
test('profile daily task shortcut opens task center and claims reward', async () => {
const user = userEvent.setup();
const onRechargeSuccess = vi.fn();
renderProfileView(onRechargeSuccess);
await user.click(screen.getByRole('button', { name: //u }));
expect(await screen.findByText('每日登录')).toBeTruthy();
expect(mockGetRpgProfileTasks).toHaveBeenCalledTimes(1);
expect(screen.getByText('1/1')).toBeTruthy();
expect(screen.getByText('+10')).toBeTruthy();
await user.click(screen.getByRole('button', { name: '领取' }));
await waitFor(() => {
expect(mockClaimRpgProfileTaskReward).toHaveBeenCalledWith('daily_login');
});
expect(onRechargeSuccess).toHaveBeenCalledTimes(1);
expect(await screen.findByText('已领取 10 光点')).toBeTruthy();
expect(
(screen.getByRole('button', { name: '已领取' }) as HTMLButtonElement)
.disabled,
).toBe(true);
});
test('profile total play time card always uses hours', () => {
renderProfileView(vi.fn(), {
totalPlayTimeMs: 90 * 60 * 1000,