mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-30 14:26:36 +08:00
5a8722ff07
接入无 URL 前缀的 zh-CN/en,顶栏与外观设置可切换语言;选择写入 cookie 后刷新生效。
193 lines
5.8 KiB
TypeScript
193 lines
5.8 KiB
TypeScript
import { fireEvent, render, screen } from '@testing-library/react';
|
|
import { NextIntlClientProvider } from 'next-intl';
|
|
import type { ReactElement } from 'react';
|
|
import { expect, it, vi } from 'vitest';
|
|
|
|
import type { WAFIPGroup, WAFRuleNode } from '@/lib/services/openflare';
|
|
import mainZh from '@/messages/zh-CN.json';
|
|
import securityZh from '@/messages/fragments/security.zh-CN.json';
|
|
|
|
import { NodeProperties } from './node-properties';
|
|
|
|
const messages = { ...mainZh, ...securityZh };
|
|
|
|
function renderWithIntl(ui: ReactElement) {
|
|
return render(
|
|
<NextIntlClientProvider
|
|
locale='zh-CN'
|
|
messages={messages}
|
|
timeZone='Asia/Shanghai'
|
|
>
|
|
{ui}
|
|
</NextIntlClientProvider>,
|
|
);
|
|
}
|
|
|
|
it('hides match and block until UA check is enabled', () => {
|
|
const node: WAFRuleNode = {
|
|
id: 'ua',
|
|
type: 'ua_check',
|
|
position: { x: 0, y: 0 },
|
|
config: {
|
|
require_ua: false,
|
|
browsers: [],
|
|
operating_systems: [],
|
|
match_mode: 'or',
|
|
block_common_bots: false,
|
|
block_abnormal_ua: false,
|
|
block_custom_ua: false,
|
|
custom_ua_patterns: [],
|
|
},
|
|
};
|
|
const onChange = vi.fn();
|
|
const { rerender } = renderWithIntl(
|
|
<NodeProperties node={node} ipGroups={[]} onChange={onChange} />,
|
|
);
|
|
expect(
|
|
screen.queryByRole('switch', { name: /屏蔽常见爬虫/ }),
|
|
).not.toBeInTheDocument();
|
|
expect(screen.queryByLabelText('浏览器')).not.toBeInTheDocument();
|
|
fireEvent.click(screen.getByRole('switch', { name: /开启 UA 检查/ }));
|
|
expect(onChange).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
config: expect.objectContaining({ require_ua: true }),
|
|
}),
|
|
);
|
|
rerender(
|
|
<NextIntlClientProvider
|
|
locale='zh-CN'
|
|
messages={messages}
|
|
timeZone='Asia/Shanghai'
|
|
>
|
|
<NodeProperties
|
|
node={{ ...node, config: { ...node.config, require_ua: true } }}
|
|
ipGroups={[]}
|
|
onChange={onChange}
|
|
/>
|
|
</NextIntlClientProvider>,
|
|
);
|
|
expect(
|
|
screen.getByRole('switch', { name: /屏蔽常见爬虫/ }),
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.getByRole('switch', { name: /屏蔽非正常/ }),
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.getByRole('switch', { name: /屏蔽自定义/ }),
|
|
).toBeInTheDocument();
|
|
expect(screen.getAllByLabelText('说明').length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('edits display name for configurable nodes', () => {
|
|
const node: WAFRuleNode = {
|
|
id: 'match',
|
|
type: 'ip_match',
|
|
position: { x: 0, y: 0 },
|
|
config: { ips: [], cidrs: [], ip_group_ids: [] },
|
|
};
|
|
const onChange = vi.fn();
|
|
renderWithIntl(
|
|
<NodeProperties node={node} ipGroups={[]} onChange={onChange} />,
|
|
);
|
|
fireEvent.change(screen.getByLabelText('显示名称'), {
|
|
target: { value: '内网放行' },
|
|
});
|
|
expect(onChange).toHaveBeenCalledWith(
|
|
expect.objectContaining({ label: '内网放行' }),
|
|
);
|
|
});
|
|
|
|
it('hides display name for system nodes', () => {
|
|
const node: WAFRuleNode = {
|
|
id: 'start',
|
|
type: 'start',
|
|
position: { x: 0, y: 0 },
|
|
config: {},
|
|
};
|
|
renderWithIntl(
|
|
<NodeProperties node={node} ipGroups={[]} onChange={vi.fn()} />,
|
|
);
|
|
expect(screen.queryByLabelText('显示名称')).not.toBeInTheDocument();
|
|
expect(screen.getByText('系统节点无需配置。')).toBeInTheDocument();
|
|
});
|
|
|
|
it('edits IP group config through a typed multi-select', async () => {
|
|
const node: WAFRuleNode = {
|
|
id: 'match',
|
|
type: 'ip_match',
|
|
position: { x: 0, y: 0 },
|
|
config: { ips: [], cidrs: [], ip_group_ids: [] },
|
|
};
|
|
const group = { id: 7, name: '办公室出口' } as WAFIPGroup;
|
|
const onChange = vi.fn();
|
|
renderWithIntl(
|
|
<NodeProperties node={node} ipGroups={[group]} onChange={onChange} />,
|
|
);
|
|
fireEvent.click(screen.getByRole('button', { name: 'IP 组' }));
|
|
fireEvent.click(await screen.findByText('办公室出口'));
|
|
expect(onChange).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
config: expect.objectContaining({ ip_group_ids: [7] }),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('associates numeric property labels and constrains server ranges', () => {
|
|
const node: WAFRuleNode = {
|
|
id: 'pow',
|
|
type: 'pow',
|
|
position: { x: 0, y: 0 },
|
|
config: {
|
|
algorithm: 'fast',
|
|
difficulty: 4,
|
|
session_ttl: 60,
|
|
challenge_ttl: 30,
|
|
},
|
|
};
|
|
renderWithIntl(
|
|
<NodeProperties node={node} ipGroups={[]} onChange={vi.fn()} />,
|
|
);
|
|
expect(screen.getByLabelText('难度')).toHaveAttribute('min', '1');
|
|
expect(screen.getByLabelText('难度')).toHaveAttribute('max', '16');
|
|
expect(screen.getByLabelText('会话 TTL(秒)')).toHaveAttribute('min', '60');
|
|
});
|
|
|
|
it('creates any normalized valid geography code', async () => {
|
|
const node: WAFRuleNode = {
|
|
id: 'geo',
|
|
type: 'geo_match',
|
|
position: { x: 0, y: 0 },
|
|
config: { countries: [], regions: [] },
|
|
};
|
|
const onChange = vi.fn();
|
|
renderWithIntl(
|
|
<NodeProperties node={node} ipGroups={[]} onChange={onChange} />,
|
|
);
|
|
fireEvent.click(screen.getByRole('button', { name: '国家代码' }));
|
|
fireEvent.change(await screen.findByPlaceholderText('搜索名称或代码'), {
|
|
target: { value: 'nz' },
|
|
});
|
|
fireEvent.click(screen.getByRole('button', { name: '添加代码' }));
|
|
expect(onChange).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
config: expect.objectContaining({ countries: ['NZ'] }),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('shows localized country names together with their codes', async () => {
|
|
const node: WAFRuleNode = {
|
|
id: 'geo',
|
|
type: 'geo_match',
|
|
position: { x: 0, y: 0 },
|
|
config: { countries: [], regions: [] },
|
|
};
|
|
renderWithIntl(
|
|
<NodeProperties node={node} ipGroups={[]} onChange={vi.fn()} />,
|
|
);
|
|
fireEvent.click(screen.getByRole('button', { name: '国家代码' }));
|
|
expect(await screen.findByText('中国')).toBeInTheDocument();
|
|
expect(screen.getByText('CN')).toBeInTheDocument();
|
|
expect(screen.getByText(/共 249 个国家\/地区/)).toBeInTheDocument();
|
|
});
|