1a106eadef
- 后端:module-runtime 的 daily_free_points_per_day 校验由「必须大于 0」放宽为只校验上界,错误变体改名 DailyFreePointsPerDayOverflow - 前端共享层:mudPoints 新增 shouldShowProfileDailyFreePool,判定 remaining > 0 || reset > 0,判定收口一处 - 钱包入口:PlatformMudPointWalletEntry 在每日免费发放额为 0 且无存量时隐藏该行 - 充值弹层:PlatformProfileRechargeModal 池概览按可见池渲染(三列变两列),扣点顺序提示与泥点确认页文案随可见性切换 - Admin Web:账号配置页每日免费泥点允许填 0(校验、min 与文案同步) - 测试:删除「每日免费必然存在」断言,新增隐藏 / 有存量仍显示 / 发放额为正三类用例,并修正钱包入口测试在 HEAD 上失效的选择器 - 文档:更新会员与泥点前端改造设计文档 §14 与 shared-memory 决策记录
147 lines
4.5 KiB
TypeScript
147 lines
4.5 KiB
TypeScript
/* @vitest-environment jsdom */
|
|
|
|
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { beforeEach, expect, test, vi } from 'vitest';
|
|
|
|
import {
|
|
getProfileWalletConfig,
|
|
upsertProfileWalletConfig,
|
|
} from '../api/adminApiClient';
|
|
import type { ProfileWalletConfigAdminResponse } from '../api/adminApiTypes';
|
|
import { AdminProfileWalletConfigPage } from './AdminProfileWalletConfigPage';
|
|
|
|
vi.mock('../api/adminApiClient', () => ({
|
|
formatAdminApiError: vi.fn((error: unknown) =>
|
|
error instanceof Error ? error.message : '请求失败',
|
|
),
|
|
getProfileWalletConfig: vi.fn(),
|
|
isAdminApiError: vi.fn(() => false),
|
|
upsertProfileWalletConfig: vi.fn(),
|
|
}));
|
|
|
|
const configResponse: ProfileWalletConfigAdminResponse = {
|
|
configId: 'profile_wallet',
|
|
initialMudPoints: 100,
|
|
dailyFreePointsPerDay: 20,
|
|
createdBy: 'owner-1',
|
|
createdByDisplayName: '管理员',
|
|
createdAt: '2026-07-31T01:00:00Z',
|
|
updatedBy: 'owner-1',
|
|
updatedByDisplayName: '管理员',
|
|
updatedAt: '2026-07-31T01:00:00Z',
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
vi.mocked(getProfileWalletConfig).mockResolvedValue(configResponse);
|
|
vi.mocked(upsertProfileWalletConfig).mockResolvedValue({
|
|
...configResponse,
|
|
initialMudPoints: 120,
|
|
dailyFreePointsPerDay: 35,
|
|
});
|
|
});
|
|
|
|
test('账号配置页加载并展示每日免费泥点', async () => {
|
|
render(
|
|
<AdminProfileWalletConfigPage
|
|
token="admin-token"
|
|
result={configResponse}
|
|
onUnauthorized={vi.fn()}
|
|
onResultChange={vi.fn()}
|
|
/>,
|
|
);
|
|
expect(
|
|
((await screen.findByLabelText('每日免费泥点数')) as HTMLInputElement)
|
|
.value,
|
|
).toBe('20');
|
|
expect(getProfileWalletConfig).toHaveBeenCalledWith('admin-token');
|
|
expect(screen.getByText('每日免费泥点')).toBeTruthy();
|
|
});
|
|
|
|
test('账号配置页一次保存初始和每日免费泥点', async () => {
|
|
const user = userEvent.setup();
|
|
const onResultChange = vi.fn();
|
|
render(
|
|
<AdminProfileWalletConfigPage
|
|
token="admin-token"
|
|
result={configResponse}
|
|
onUnauthorized={vi.fn()}
|
|
onResultChange={onResultChange}
|
|
/>,
|
|
);
|
|
await screen.findByLabelText('每日免费泥点数');
|
|
fireEvent.change(screen.getByLabelText('账号初始泥点数'), {
|
|
target: { value: '120' },
|
|
});
|
|
fireEvent.change(screen.getByLabelText('每日免费泥点数'), {
|
|
target: { value: '35' },
|
|
});
|
|
await user.click(screen.getByRole('button', { name: '保存' }));
|
|
expect(screen.getByText('初始 120 泥点,每日免费 35 泥点')).toBeTruthy();
|
|
await user.click(screen.getByRole('button', { name: '确认' }));
|
|
await waitFor(() =>
|
|
expect(upsertProfileWalletConfig).toHaveBeenCalledWith('admin-token', {
|
|
initialMudPoints: 120,
|
|
dailyFreePointsPerDay: 35,
|
|
}),
|
|
);
|
|
expect(onResultChange).toHaveBeenLastCalledWith(
|
|
expect.objectContaining({
|
|
initialMudPoints: 120,
|
|
dailyFreePointsPerDay: 35,
|
|
}),
|
|
);
|
|
});
|
|
|
|
test('账号配置页拒绝负数或非整数每日免费额度', async () => {
|
|
render(
|
|
<AdminProfileWalletConfigPage
|
|
token="admin-token"
|
|
result={configResponse}
|
|
onUnauthorized={vi.fn()}
|
|
onResultChange={vi.fn()}
|
|
/>,
|
|
);
|
|
const input = await screen.findByLabelText('每日免费泥点数');
|
|
fireEvent.change(input, { target: { value: '1.5' } });
|
|
expect(
|
|
(screen.getByRole('button', { name: '保存' }) as HTMLButtonElement)
|
|
.disabled,
|
|
).toBe(true);
|
|
fireEvent.change(input, { target: { value: '-1' } });
|
|
expect(
|
|
(screen.getByRole('button', { name: '保存' }) as HTMLButtonElement)
|
|
.disabled,
|
|
).toBe(true);
|
|
expect(upsertProfileWalletConfig).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('账号配置页允许把每日免费泥点配置为 0', async () => {
|
|
const user = userEvent.setup();
|
|
vi.mocked(upsertProfileWalletConfig).mockResolvedValue({
|
|
...configResponse,
|
|
dailyFreePointsPerDay: 0,
|
|
});
|
|
render(
|
|
<AdminProfileWalletConfigPage
|
|
token="admin-token"
|
|
result={configResponse}
|
|
onUnauthorized={vi.fn()}
|
|
onResultChange={vi.fn()}
|
|
/>,
|
|
);
|
|
fireEvent.change(await screen.findByLabelText('每日免费泥点数'), {
|
|
target: { value: '0' },
|
|
});
|
|
await user.click(screen.getByRole('button', { name: '保存' }));
|
|
expect(screen.getByText('初始 100 泥点,每日免费 0 泥点')).toBeTruthy();
|
|
await user.click(screen.getByRole('button', { name: '确认' }));
|
|
await waitFor(() =>
|
|
expect(upsertProfileWalletConfig).toHaveBeenCalledWith('admin-token', {
|
|
initialMudPoints: 100,
|
|
dailyFreePointsPerDay: 0,
|
|
}),
|
|
);
|
|
});
|