- 新增许可证服务器 (license-server/) - 新增 Agent 部署模块 (flnxi-agent/) - 添加许可证验证和激活页面 - 添加 Harbor 镜像同步脚本 - 更新素材系统支持许可证验证
245 lines
7.8 KiB
TypeScript
245 lines
7.8 KiB
TypeScript
/**
|
||
* @jest-environment jsdom
|
||
*/
|
||
/**
|
||
* 激活页面测试
|
||
* 测试许可证激活和免费试用功能
|
||
*/
|
||
import { render, screen, fireEvent, waitFor, act } from '@testing-library/react';
|
||
import ActivatePage from '../page';
|
||
|
||
// Mock next/navigation
|
||
const mockPush = jest.fn();
|
||
jest.mock('next/navigation', () => ({
|
||
useRouter: () => ({
|
||
push: mockPush,
|
||
}),
|
||
}));
|
||
|
||
// Mock fetch
|
||
global.fetch = jest.fn();
|
||
|
||
describe('ActivatePage', () => {
|
||
beforeEach(() => {
|
||
jest.clearAllMocks();
|
||
(global.fetch as jest.Mock).mockReset();
|
||
});
|
||
|
||
describe('渲染测试', () => {
|
||
it('应该正确渲染页面标题和表单', () => {
|
||
render(<ActivatePage />);
|
||
|
||
expect(screen.getByText('FLNXI 素材系统')).toBeInTheDocument();
|
||
expect(screen.getByText('请激活您的许可证')).toBeInTheDocument();
|
||
expect(screen.getByPlaceholderText('XXXX-XXXX-XXXX-XXXX')).toBeInTheDocument();
|
||
expect(screen.getByText('激活许可证')).toBeInTheDocument();
|
||
expect(screen.getByText('免费试用')).toBeInTheDocument();
|
||
});
|
||
|
||
it('应该显示免费版限制说明', () => {
|
||
render(<ActivatePage />);
|
||
expect(screen.getByText('免费版限制:10 个用户、100 个素材')).toBeInTheDocument();
|
||
});
|
||
|
||
it('应该显示联系信息', () => {
|
||
render(<ActivatePage />);
|
||
expect(screen.getByText('需要购买许可证?请联系我们')).toBeInTheDocument();
|
||
});
|
||
});
|
||
|
||
describe('许可证密钥格式化', () => {
|
||
it('应该自动将输入转换为大写', () => {
|
||
render(<ActivatePage />);
|
||
const input = screen.getByPlaceholderText('XXXX-XXXX-XXXX-XXXX') as HTMLInputElement;
|
||
|
||
fireEvent.change(input, { target: { value: 'abcd' } });
|
||
expect(input.value).toBe('ABCD');
|
||
});
|
||
|
||
it('应该自动添加横杠分隔符', () => {
|
||
render(<ActivatePage />);
|
||
const input = screen.getByPlaceholderText('XXXX-XXXX-XXXX-XXXX') as HTMLInputElement;
|
||
|
||
fireEvent.change(input, { target: { value: 'abcd1234' } });
|
||
expect(input.value).toBe('ABCD-1234');
|
||
});
|
||
|
||
it('应该过滤非字母数字字符', () => {
|
||
render(<ActivatePage />);
|
||
const input = screen.getByPlaceholderText('XXXX-XXXX-XXXX-XXXX') as HTMLInputElement;
|
||
|
||
fireEvent.change(input, { target: { value: 'ab!@#cd12' } });
|
||
expect(input.value).toBe('ABCD-12');
|
||
});
|
||
|
||
it('应该限制最大长度为19个字符(含横杠)', () => {
|
||
render(<ActivatePage />);
|
||
const input = screen.getByPlaceholderText('XXXX-XXXX-XXXX-XXXX') as HTMLInputElement;
|
||
|
||
fireEvent.change(input, { target: { value: 'ABCD1234EFGH5678EXTRA' } });
|
||
expect(input.value).toBe('ABCD-1234-EFGH-5678');
|
||
});
|
||
});
|
||
|
||
describe('激活按钮状态', () => {
|
||
it('密钥不完整时激活按钮应该禁用', () => {
|
||
render(<ActivatePage />);
|
||
const button = screen.getByText('激活许可证');
|
||
expect(button).toBeDisabled();
|
||
});
|
||
|
||
it('密钥完整时激活按钮应该启用', () => {
|
||
render(<ActivatePage />);
|
||
const input = screen.getByPlaceholderText('XXXX-XXXX-XXXX-XXXX');
|
||
|
||
fireEvent.change(input, { target: { value: 'ABCD1234EFGH5678' } });
|
||
|
||
const button = screen.getByText('激活许可证');
|
||
expect(button).not.toBeDisabled();
|
||
});
|
||
});
|
||
|
||
describe('许可证激活', () => {
|
||
it('激活成功后应该跳转到首页', async () => {
|
||
(global.fetch as jest.Mock).mockResolvedValueOnce({
|
||
json: () => Promise.resolve({ success: true }),
|
||
});
|
||
|
||
render(<ActivatePage />);
|
||
const input = screen.getByPlaceholderText('XXXX-XXXX-XXXX-XXXX');
|
||
fireEvent.change(input, { target: { value: 'ABCD1234EFGH5678' } });
|
||
|
||
const button = screen.getByText('激活许可证');
|
||
await act(async () => {
|
||
fireEvent.click(button);
|
||
});
|
||
|
||
await waitFor(() => {
|
||
expect(mockPush).toHaveBeenCalledWith('/');
|
||
});
|
||
});
|
||
|
||
it('激活失败应该显示错误信息', async () => {
|
||
(global.fetch as jest.Mock).mockResolvedValueOnce({
|
||
json: () => Promise.resolve({ success: false, error: '许可证无效' }),
|
||
});
|
||
|
||
render(<ActivatePage />);
|
||
const input = screen.getByPlaceholderText('XXXX-XXXX-XXXX-XXXX');
|
||
fireEvent.change(input, { target: { value: 'ABCD1234EFGH5678' } });
|
||
|
||
const button = screen.getByText('激活许可证');
|
||
await act(async () => {
|
||
fireEvent.click(button);
|
||
});
|
||
|
||
await waitFor(() => {
|
||
expect(screen.getByText('许可证无效')).toBeInTheDocument();
|
||
});
|
||
});
|
||
|
||
it('网络错误应该显示网络错误提示', async () => {
|
||
(global.fetch as jest.Mock).mockRejectedValueOnce(new Error('Network error'));
|
||
|
||
render(<ActivatePage />);
|
||
const input = screen.getByPlaceholderText('XXXX-XXXX-XXXX-XXXX');
|
||
fireEvent.change(input, { target: { value: 'ABCD1234EFGH5678' } });
|
||
|
||
const button = screen.getByText('激活许可证');
|
||
await act(async () => {
|
||
fireEvent.click(button);
|
||
});
|
||
|
||
await waitFor(() => {
|
||
expect(screen.getByText('网络错误,请检查网络连接')).toBeInTheDocument();
|
||
});
|
||
});
|
||
|
||
it('激活时应该显示加载状态', async () => {
|
||
let resolvePromise: (value: unknown) => void;
|
||
(global.fetch as jest.Mock).mockImplementation(() =>
|
||
new Promise(resolve => { resolvePromise = resolve; })
|
||
);
|
||
|
||
render(<ActivatePage />);
|
||
const input = screen.getByPlaceholderText('XXXX-XXXX-XXXX-XXXX');
|
||
fireEvent.change(input, { target: { value: 'ABCD1234EFGH5678' } });
|
||
|
||
const button = screen.getByText('激活许可证');
|
||
await act(async () => {
|
||
fireEvent.click(button);
|
||
});
|
||
|
||
expect(screen.getByText('激活中...')).toBeInTheDocument();
|
||
|
||
// 清理
|
||
await act(async () => {
|
||
resolvePromise!({ json: () => Promise.resolve({ success: true }) });
|
||
});
|
||
});
|
||
});
|
||
|
||
describe('免费试用', () => {
|
||
it('免费试用成功后应该跳转到首页', async () => {
|
||
(global.fetch as jest.Mock).mockResolvedValueOnce({
|
||
json: () => Promise.resolve({ success: true }),
|
||
});
|
||
|
||
render(<ActivatePage />);
|
||
const button = screen.getByText('免费试用');
|
||
await act(async () => {
|
||
fireEvent.click(button);
|
||
});
|
||
|
||
await waitFor(() => {
|
||
expect(mockPush).toHaveBeenCalledWith('/');
|
||
});
|
||
|
||
expect(global.fetch).toHaveBeenCalledWith('/api/license/activate-free', {
|
||
method: 'POST',
|
||
});
|
||
});
|
||
|
||
it('免费试用失败应该显示错误信息', async () => {
|
||
(global.fetch as jest.Mock).mockResolvedValueOnce({
|
||
json: () => Promise.resolve({ success: false, error: '试用已过期' }),
|
||
});
|
||
|
||
render(<ActivatePage />);
|
||
const button = screen.getByText('免费试用');
|
||
await act(async () => {
|
||
fireEvent.click(button);
|
||
});
|
||
|
||
await waitFor(() => {
|
||
expect(screen.getByText('试用已过期')).toBeInTheDocument();
|
||
});
|
||
});
|
||
});
|
||
|
||
describe('API 调用', () => {
|
||
it('激活时应该发送正确的请求', async () => {
|
||
(global.fetch as jest.Mock).mockResolvedValueOnce({
|
||
json: () => Promise.resolve({ success: true }),
|
||
});
|
||
|
||
render(<ActivatePage />);
|
||
const input = screen.getByPlaceholderText('XXXX-XXXX-XXXX-XXXX');
|
||
fireEvent.change(input, { target: { value: 'ABCD1234EFGH5678' } });
|
||
|
||
const button = screen.getByText('激活许可证');
|
||
await act(async () => {
|
||
fireEvent.click(button);
|
||
});
|
||
|
||
await waitFor(() => {
|
||
expect(global.fetch).toHaveBeenCalledWith('/api/license/activate', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ licenseKey: 'ABCD-1234-EFGH-5678' }),
|
||
});
|
||
});
|
||
});
|
||
});
|
||
});
|