merge master into codex/wechat-mini-program-virtual-payment
This commit is contained in:
@@ -141,7 +141,6 @@ const {
|
||||
amountDelta: 10,
|
||||
balanceAfter: 10,
|
||||
sourceType: 'daily_task_reward',
|
||||
createdAt: '2026-05-03T08:01:00Z',
|
||||
},
|
||||
center: buildClaimedTaskCenter(),
|
||||
})),
|
||||
@@ -204,9 +203,9 @@ const {
|
||||
amountCents: 600,
|
||||
status: 'paid',
|
||||
paymentChannel: 'mock',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
paidAt: '2026-04-25T10:00:00Z',
|
||||
providerTransactionId: null,
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
pointsDelta: 120,
|
||||
membershipExpiresAt: null,
|
||||
},
|
||||
@@ -237,9 +236,9 @@ const {
|
||||
amountCents: 600,
|
||||
status: 'paid',
|
||||
paymentChannel: 'wechat_mp_virtual',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
paidAt: '2026-04-25T10:01:00Z',
|
||||
providerTransactionId: 'wx-transaction-1',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
pointsDelta: 120,
|
||||
membershipExpiresAt: null,
|
||||
},
|
||||
@@ -276,8 +275,8 @@ const {
|
||||
amountCents: 600,
|
||||
status: 'paid',
|
||||
paymentChannel: 'wechat_mp_virtual',
|
||||
providerTransactionId: 'wx-transaction-1',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
providerTransactionId: 'wx-transaction-1',
|
||||
paidAt: '2026-04-25T10:01:00Z',
|
||||
pointsDelta: 120,
|
||||
membershipExpiresAt: null,
|
||||
@@ -305,14 +304,12 @@ const {
|
||||
amountDelta: -1,
|
||||
balanceAfter: 29,
|
||||
sourceType: 'asset_operation_consume',
|
||||
createdAt: '2026-04-28T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: 'ledger-2',
|
||||
amountDelta: 30,
|
||||
balanceAfter: 30,
|
||||
sourceType: 'invite_invitee_reward',
|
||||
createdAt: '2026-04-28T09:00:00Z',
|
||||
},
|
||||
],
|
||||
})),
|
||||
@@ -328,6 +325,7 @@ const {
|
||||
async (code: string): Promise<PublicUserSummary> => ({
|
||||
id: `id-${code}`,
|
||||
publicUserCode: code,
|
||||
username: 'author_user',
|
||||
displayName: '公开作者',
|
||||
avatarUrl: null,
|
||||
}),
|
||||
@@ -336,6 +334,7 @@ const {
|
||||
async (userId: string): Promise<PublicUserSummary> => ({
|
||||
id: userId,
|
||||
publicUserCode: `code-${userId}`,
|
||||
username: 'author_user',
|
||||
displayName: '公开作者',
|
||||
avatarUrl: null,
|
||||
}),
|
||||
@@ -362,14 +361,12 @@ vi.mock('../../services/payment/paymentRedirect', () => ({
|
||||
mockUpdateAuthProfile.mockResolvedValue({
|
||||
id: 'user-1',
|
||||
publicUserCode: '100001',
|
||||
username: 'tester',
|
||||
displayName: '测试玩家',
|
||||
avatarUrl: null,
|
||||
phoneNumberMasked: null,
|
||||
loginMethod: 'password',
|
||||
bindingStatus: 'active',
|
||||
wechatBound: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
});
|
||||
|
||||
vi.mock('../../services/rpg-entry/rpgProfileClient', () => ({
|
||||
@@ -723,14 +720,12 @@ function ProfileHomeViewHarness({
|
||||
user: {
|
||||
id: 'user-1',
|
||||
publicUserCode: '100001',
|
||||
username: 'tester',
|
||||
displayName: '测试玩家',
|
||||
avatarUrl: null,
|
||||
phoneNumberMasked: null,
|
||||
loginMethod: 'password',
|
||||
bindingStatus: 'active',
|
||||
wechatBound: false,
|
||||
createdAt: DEFAULT_PROFILE_CREATED_AT,
|
||||
...userOverrides,
|
||||
},
|
||||
canAccessProtectedData: true,
|
||||
@@ -911,14 +906,12 @@ function renderLoggedInHomeView(
|
||||
user: {
|
||||
id: 'user-1',
|
||||
publicUserCode: '100001',
|
||||
username: 'tester',
|
||||
displayName: '测试玩家',
|
||||
avatarUrl: null,
|
||||
phoneNumberMasked: null,
|
||||
loginMethod: 'password',
|
||||
bindingStatus: 'active',
|
||||
wechatBound: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
canAccessProtectedData: true,
|
||||
openLoginModal: vi.fn(),
|
||||
@@ -1095,7 +1088,6 @@ afterEach(() => {
|
||||
amountDelta: 10,
|
||||
balanceAfter: 10,
|
||||
sourceType: 'daily_task_reward',
|
||||
createdAt: '2026-05-03T08:01:00Z',
|
||||
},
|
||||
center: mockBuildTaskCenter({
|
||||
walletBalance: 10,
|
||||
@@ -1121,14 +1113,12 @@ afterEach(() => {
|
||||
mockUpdateAuthProfile.mockResolvedValue({
|
||||
id: 'user-1',
|
||||
publicUserCode: '100001',
|
||||
username: 'tester',
|
||||
displayName: '测试玩家',
|
||||
avatarUrl: null,
|
||||
phoneNumberMasked: null,
|
||||
loginMethod: 'password',
|
||||
bindingStatus: 'active',
|
||||
wechatBound: false,
|
||||
createdAt: DEFAULT_PROFILE_CREATED_AT,
|
||||
});
|
||||
mockQrCodeToDataUrl.mockResolvedValue('data:image/png;base64,QR');
|
||||
mockRedirectToPaymentUrl.mockReset();
|
||||
@@ -1190,9 +1180,9 @@ test('profile recharge modal shows native qr code on desktop web by default', as
|
||||
amountCents: 600,
|
||||
status: 'pending' as const,
|
||||
paymentChannel: 'wechat_native',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
paidAt: null,
|
||||
providerTransactionId: null,
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
pointsDelta: 0,
|
||||
membershipExpiresAt: null,
|
||||
},
|
||||
@@ -1255,9 +1245,9 @@ test('profile recharge modal jumps to h5 payment on mobile web by default', asyn
|
||||
amountCents: 600,
|
||||
status: 'pending' as const,
|
||||
paymentChannel: 'wechat_h5',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
paidAt: null,
|
||||
providerTransactionId: null,
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
pointsDelta: 0,
|
||||
membershipExpiresAt: null,
|
||||
},
|
||||
@@ -1367,9 +1357,9 @@ test('profile recharge modal posts virtual payment params in mini program web-vi
|
||||
amountCents: 600,
|
||||
status: 'pending' as const,
|
||||
paymentChannel: 'wechat_mp_virtual',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
paidAt: null as string | null,
|
||||
providerTransactionId: null,
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
pointsDelta: 0,
|
||||
membershipExpiresAt: null,
|
||||
},
|
||||
@@ -1820,9 +1810,9 @@ test('profile recharge modal waits for paid confirmation before refreshing dashb
|
||||
amountCents: 600,
|
||||
status: 'pending' as const,
|
||||
paymentChannel: 'wechat_mp_virtual',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
paidAt: null as string | null,
|
||||
providerTransactionId: null,
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
pointsDelta: 0,
|
||||
membershipExpiresAt: null,
|
||||
},
|
||||
@@ -1859,9 +1849,9 @@ test('profile recharge modal waits for paid confirmation before refreshing dashb
|
||||
amountCents: 600,
|
||||
status: 'pending' as const,
|
||||
paymentChannel: 'wechat_mp_virtual',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
paidAt: null,
|
||||
providerTransactionId: null,
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
pointsDelta: 0,
|
||||
membershipExpiresAt: null,
|
||||
},
|
||||
@@ -1890,9 +1880,9 @@ test('profile recharge modal waits for paid confirmation before refreshing dashb
|
||||
amountCents: 600,
|
||||
status: 'paid' as const,
|
||||
paymentChannel: 'wechat_mp_virtual',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
paidAt: '2026-04-25T10:01:00Z',
|
||||
providerTransactionId: 'wx-transaction-2',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
pointsDelta: 120,
|
||||
membershipExpiresAt: null,
|
||||
},
|
||||
@@ -1954,9 +1944,9 @@ test('profile recharge modal loads wechat js sdk before mini program payment bri
|
||||
amountCents: 600,
|
||||
status: 'pending' as const,
|
||||
paymentChannel: 'wechat_mp_virtual',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
paidAt: null as string | null,
|
||||
providerTransactionId: null,
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
pointsDelta: 0,
|
||||
membershipExpiresAt: null,
|
||||
},
|
||||
@@ -2040,9 +2030,9 @@ test('profile recharge modal releases submitting state after cancelled wechat pa
|
||||
amountCents: 600,
|
||||
status: 'pending' as const,
|
||||
paymentChannel: 'wechat_mp_virtual',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
paidAt: null as string | null,
|
||||
providerTransactionId: null,
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
pointsDelta: 0,
|
||||
membershipExpiresAt: null,
|
||||
},
|
||||
@@ -2123,9 +2113,9 @@ test('profile native qr confirmation refreshes only after server reports paid',
|
||||
amountCents: 600,
|
||||
status: 'pending' as const,
|
||||
paymentChannel: 'wechat_native',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
paidAt: null,
|
||||
providerTransactionId: null,
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
pointsDelta: 0,
|
||||
membershipExpiresAt: null,
|
||||
},
|
||||
@@ -2157,9 +2147,9 @@ test('profile native qr confirmation refreshes only after server reports paid',
|
||||
amountCents: 600,
|
||||
status: 'paid' as const,
|
||||
paymentChannel: 'wechat_native',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
paidAt: '2026-04-25T10:01:00Z',
|
||||
providerTransactionId: 'wx-native-1',
|
||||
createdAt: '2026-04-25T10:00:00Z',
|
||||
pointsDelta: 120,
|
||||
membershipExpiresAt: null,
|
||||
},
|
||||
@@ -2564,7 +2554,7 @@ test('wallet ledger modal shows empty and error states', async () => {
|
||||
test('profile community shortcut shows reward subtitle and invited users', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
renderProfileView(vi.fn(), {}, { createdAt: buildFreshProfileCreatedAt() });
|
||||
renderProfileView(vi.fn(), {});
|
||||
|
||||
expect(screen.queryByRole('button', { name: /邀请好友/u })).toBeNull();
|
||||
|
||||
@@ -2586,7 +2576,6 @@ test('profile page hides legacy redeem invite secondary shortcut for fresh accou
|
||||
renderProfileView(
|
||||
vi.fn(),
|
||||
{},
|
||||
{ createdAt: buildFreshProfileCreatedAt() },
|
||||
);
|
||||
|
||||
const communityButton = screen.getByRole('button', { name: /玩家社区/u });
|
||||
@@ -2618,7 +2607,7 @@ test('profile redeem invite shortcut hides after redeemed or one day old', async
|
||||
});
|
||||
unmount();
|
||||
|
||||
renderProfileView(vi.fn(), {}, { createdAt: '2026-04-01T00:00:00.000Z' });
|
||||
renderProfileView(vi.fn(), {});
|
||||
const expiredShortcutRegion = screen.getByRole('region', {
|
||||
name: '常用功能',
|
||||
});
|
||||
@@ -2678,7 +2667,6 @@ test('profile redeem invite query modal submits code after login', async () => {
|
||||
renderProfileView(
|
||||
onRechargeSuccess,
|
||||
{},
|
||||
{ createdAt: buildFreshProfileCreatedAt() },
|
||||
);
|
||||
|
||||
expect(await screen.findByLabelText('邀请码')).toBeTruthy();
|
||||
@@ -2837,14 +2825,12 @@ test('logged in create tab shows real wallet balance beside the brand', () => {
|
||||
user: {
|
||||
id: 'user-1',
|
||||
publicUserCode: '100001',
|
||||
username: 'tester',
|
||||
displayName: '测试玩家',
|
||||
avatarUrl: null,
|
||||
phoneNumberMasked: null,
|
||||
loginMethod: 'password',
|
||||
bindingStatus: 'active',
|
||||
wechatBound: false,
|
||||
createdAt: DEFAULT_PROFILE_CREATED_AT,
|
||||
},
|
||||
canAccessProtectedData: true,
|
||||
openLoginModal: vi.fn(),
|
||||
@@ -3335,14 +3321,12 @@ test('logged in recommend page uses gated recommend detail callback', async () =
|
||||
user: {
|
||||
id: 'user-1',
|
||||
publicUserCode: '100001',
|
||||
username: 'tester',
|
||||
displayName: '测试玩家',
|
||||
avatarUrl: null,
|
||||
phoneNumberMasked: null,
|
||||
loginMethod: 'password',
|
||||
bindingStatus: 'active',
|
||||
wechatBound: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
canAccessProtectedData: true,
|
||||
openLoginModal: vi.fn(),
|
||||
@@ -3471,14 +3455,12 @@ test('logged in recommend runtime preloads adjacent work previews and drag switc
|
||||
user: {
|
||||
id: 'user-1',
|
||||
publicUserCode: '100001',
|
||||
username: 'tester',
|
||||
displayName: '测试玩家',
|
||||
avatarUrl: null,
|
||||
phoneNumberMasked: null,
|
||||
loginMethod: 'password',
|
||||
bindingStatus: 'active',
|
||||
wechatBound: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
canAccessProtectedData: true,
|
||||
openLoginModal: vi.fn(),
|
||||
@@ -3648,6 +3630,7 @@ test('mobile recommend meta loads real author avatar from public user summary',
|
||||
mockGetPublicAuthUserById.mockResolvedValueOnce({
|
||||
id: 'user-2',
|
||||
publicUserCode: 'SY-00000002',
|
||||
username: 'puzzle_user',
|
||||
displayName: '拼图玩家',
|
||||
avatarUrl: 'data:image/png;base64,AUTHOR',
|
||||
});
|
||||
@@ -3907,14 +3890,12 @@ test('desktop logged in home syncs mobile home modules without square or latest
|
||||
user: {
|
||||
id: 'user-1',
|
||||
publicUserCode: '100001',
|
||||
username: 'tester',
|
||||
displayName: '测试玩家',
|
||||
avatarUrl: null,
|
||||
phoneNumberMasked: null,
|
||||
loginMethod: 'password',
|
||||
bindingStatus: 'active',
|
||||
wechatBound: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
canAccessProtectedData: true,
|
||||
openLoginModal: vi.fn(),
|
||||
|
||||
Reference in New Issue
Block a user