Files
lislgosms/src/apps/admin/channel-groups/RouteConfigModal.test.tsx
T

146 lines
5.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { fireEvent, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, expect, it, vi } from 'vitest';
import type { AdminChannel } from '@/api/adminApi';
import { RouteConfigModal } from './RouteConfigModal';
const channel = (id: string, overrides: Partial<AdminChannel> = {}): AdminChannel => ({
id,
name: `通道${id}`,
code: `CODE-${id}`,
carriers: ['mobile'],
sendRegion: '广东省',
gatewayHost: '127.0.0.1',
gatewayPort: 7890,
account: 'test',
srcId: '106',
rateLimitPerSecond: 1,
unitPrice: 325,
status: 'active',
...overrides,
});
describe('RouteConfigModal', () => {
it('keeps historical priority and exposes costs while permitting a disconnected active channel', async () => {
const onSubmit = vi.fn(() => null);
const current = channel('current', { connectionStates: [] });
render(
<RouteConfigModal
channels={[current]}
carrier="mobile"
modal={{ type: 'national', mode: 'edit', route: { id: 'route-1', channelId: current.id, priority: 20 } }}
occupiedChannelIds={[current.id]}
nextPriority={30}
onClose={vi.fn()}
onSubmit={onSubmit}
/>,
);
expect(screen.getByRole('spinbutton', { name: /优先级/ })).toHaveValue(20);
expect(screen.getByText('0.0325')).toBeVisible();
expect(screen.getByText('暂无连接回写')).toBeVisible();
expect(screen.getByRole('radio')).toBeEnabled();
await userEvent.click(screen.getByRole('button', { name: /^确认$/ }));
expect(onSubmit).toHaveBeenCalledWith({ id: 'route-1', channelId: 'current', priority: 20 });
});
it('shows unavailable reasons and keeps the selected channel while searching', async () => {
const channels = [
channel('available'),
channel('occupied'),
channel('deleted', { status: 'deleted' }),
channel('telecom', { carriers: ['telecom'] }),
channel('disabled', { status: 'disabled' }),
];
render(
<RouteConfigModal
channels={channels}
carrier="mobile"
modal={{ type: 'national', mode: 'create' }}
occupiedChannelIds={['occupied']}
nextPriority={30}
onClose={vi.fn()}
onSubmit={() => null}
/>,
);
for (const id of ['occupied', 'deleted', 'telecom'])
expect(screen.getByRole('radio', { name: new RegExp(`CODE-${id}`) })).toBeDisabled();
expect(screen.getByText('已在当前通道组中配置')).toBeVisible();
expect(screen.getByText('通道已删除')).toBeVisible();
expect(screen.getByText('不支持移动')).toBeVisible();
expect(screen.getByText('已停用')).toBeVisible();
expect(screen.getByRole('radio', { name: /CODE-disabled/ })).toBeEnabled();
await userEvent.click(screen.getByRole('radio', { name: /CODE-available/ }));
await userEvent.type(screen.getByRole('textbox', { name: '搜索通道' }), 'CODE-telecom');
expect(screen.getAllByRole('radio')).toHaveLength(1);
expect(screen.getByText('已选:通道availableCODE-available')).toBeVisible();
});
it('disables region mismatches but preserves a historical province option', () => {
render(
<RouteConfigModal
channels={[channel('other', { sendRegion: '江苏省' })]}
carrier="mobile"
modal={{ type: 'province', mode: 'edit', route: { id: 'p-1', channelId: 'missing', province: '浙江省' } }}
occupiedChannelIds={[]}
nextPriority={10}
onClose={vi.fn()}
onSubmit={() => null}
/>,
);
expect(screen.getByText('浙江省')).toBeVisible();
expect(screen.getByRole('radio')).toBeDisabled();
expect(screen.getByText('通道地区与所选省份不匹配')).toBeVisible();
expect(screen.getByRole('alert')).toHaveTextContent('原通道不存在,请重新选择');
});
it('retains form values after parent conflict rejection and rejects a fractional priority', async () => {
const onSubmit = vi.fn(() => '同一通道组内全国通道优先级不能重复');
const onClose = vi.fn();
render(
<RouteConfigModal
channels={[channel('1')]}
carrier="mobile"
modal={{ type: 'national', mode: 'create' }}
occupiedChannelIds={[]}
nextPriority={20}
onClose={onClose}
onSubmit={onSubmit}
/>,
);
await userEvent.click(screen.getByRole('radio'));
await userEvent.click(screen.getByRole('button', { name: /^确认$/ }));
expect(screen.getByRole('alert')).toHaveTextContent('优先级不能重复');
expect(screen.getByRole('radio')).toBeChecked();
expect(onClose).not.toHaveBeenCalled();
const input = screen.getByRole('spinbutton', { name: /优先级/ });
fireEvent.change(input, { target: { value: '1.5' } });
await userEvent.click(screen.getByRole('button', { name: /^确认$/ }));
expect(screen.getByRole('alert')).toHaveTextContent('整数');
expect(onSubmit).toHaveBeenCalledTimes(1);
fireEvent.change(input, { target: { value: '-10' } });
await userEvent.click(screen.getByRole('button', { name: /^确认$/ }));
expect(onSubmit).toHaveBeenLastCalledWith(expect.objectContaining({ priority: -10 }));
});
it('uses the shared unsaved guard when dismissing a changed selection', async () => {
const onClose = vi.fn();
render(
<RouteConfigModal
channels={[channel('1')]}
carrier="mobile"
modal={{ type: 'national', mode: 'create' }}
occupiedChannelIds={[]}
nextPriority={10}
onClose={onClose}
onSubmit={() => null}
/>,
);
await userEvent.click(screen.getByRole('radio'));
await userEvent.click(screen.getByRole('button', { name: /^取消$/ }));
expect(screen.getByRole('alertdialog')).toHaveTextContent('放弃未保存的修改');
expect(onClose).not.toHaveBeenCalled();
await userEvent.click(screen.getByRole('button', { name: '继续编辑' }));
expect(screen.getByRole('radio')).toBeChecked();
});
});