|
@@ -3,81 +3,7 @@ import { render, screen, fireEvent, waitFor, within } from '@testing-library/rea
|
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
|
import SalaryManagement from '../../src/components/SalaryManagement';
|
|
import SalaryManagement from '../../src/components/SalaryManagement';
|
|
|
import { salaryClientManager } from '../../src/api/salaryClient';
|
|
import { salaryClientManager } from '../../src/api/salaryClient';
|
|
|
-// AreaSelect is mocked below
|
|
|
|
|
-
|
|
|
|
|
-// Mock AreaSelect组件 - 改进版本,包含区县字段
|
|
|
|
|
-vi.mock('@d8d/area-management-ui/components', () => ({
|
|
|
|
|
- AreaSelect: vi.fn(({ value, onChange, disabled, required }) => {
|
|
|
|
|
- // 记录required参数,用于验证
|
|
|
|
|
- console.debug('AreaSelect called with required:', required);
|
|
|
|
|
-
|
|
|
|
|
- return (
|
|
|
|
|
- <div data-testid="area-select" data-required={required}>
|
|
|
|
|
- <select
|
|
|
|
|
- data-testid="province-select"
|
|
|
|
|
- value={value?.provinceId || ''}
|
|
|
|
|
- onChange={(e) => {
|
|
|
|
|
- const newValue = {
|
|
|
|
|
- provinceId: e.target.value ? Number(e.target.value) : undefined,
|
|
|
|
|
- cityId: undefined,
|
|
|
|
|
- districtId: undefined
|
|
|
|
|
- };
|
|
|
|
|
- onChange?.(newValue);
|
|
|
|
|
- }}
|
|
|
|
|
- disabled={disabled}
|
|
|
|
|
- >
|
|
|
|
|
- <option value="">选择省份</option>
|
|
|
|
|
- <option value="110000">北京市</option>
|
|
|
|
|
- <option value="310000">上海市</option>
|
|
|
|
|
- <option value="440000">广东省</option>
|
|
|
|
|
- </select>
|
|
|
|
|
- <select
|
|
|
|
|
- data-testid="city-select"
|
|
|
|
|
- value={value?.cityId || ''}
|
|
|
|
|
- onChange={(e) => {
|
|
|
|
|
- const newValue = {
|
|
|
|
|
- provinceId: value?.provinceId,
|
|
|
|
|
- cityId: e.target.value ? Number(e.target.value) : undefined,
|
|
|
|
|
- districtId: undefined
|
|
|
|
|
- };
|
|
|
|
|
- onChange?.(newValue);
|
|
|
|
|
- }}
|
|
|
|
|
- disabled={disabled || !value?.provinceId}
|
|
|
|
|
- >
|
|
|
|
|
- <option value="">选择城市</option>
|
|
|
|
|
- <option value="110100">北京市辖区</option>
|
|
|
|
|
- <option value="310100">上海市辖区</option>
|
|
|
|
|
- <option value="440100">广州市</option>
|
|
|
|
|
- </select>
|
|
|
|
|
- <select
|
|
|
|
|
- data-testid="district-select"
|
|
|
|
|
- value={value?.districtId || ''}
|
|
|
|
|
- onChange={(e) => {
|
|
|
|
|
- const newValue = {
|
|
|
|
|
- provinceId: value?.provinceId,
|
|
|
|
|
- cityId: value?.cityId,
|
|
|
|
|
- districtId: e.target.value ? Number(e.target.value) : undefined
|
|
|
|
|
- };
|
|
|
|
|
- onChange?.(newValue);
|
|
|
|
|
- }}
|
|
|
|
|
- disabled={disabled || !value?.cityId}
|
|
|
|
|
- >
|
|
|
|
|
- <option value="">选择区县</option>
|
|
|
|
|
- <option value="110101">东城区</option>
|
|
|
|
|
- <option value="110102">西城区</option>
|
|
|
|
|
- <option value="310101">黄浦区</option>
|
|
|
|
|
- <option value="440103">荔湾区</option>
|
|
|
|
|
- </select>
|
|
|
|
|
- {/* 显示required参数状态 */}
|
|
|
|
|
- <div data-testid="required-status">
|
|
|
|
|
- 省份必填: {required ? '是' : '否'},
|
|
|
|
|
- 城市必填: {required && value?.provinceId ? '是' : '否'},
|
|
|
|
|
- 区县必填: 否
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- );
|
|
|
|
|
- })
|
|
|
|
|
-}));
|
|
|
|
|
|
|
+// 使用实际的AreaSelect组件,不mock
|
|
|
|
|
|
|
|
// 完整的mock响应对象
|
|
// 完整的mock响应对象
|
|
|
const createMockResponse = (status: number, data?: any) => ({
|
|
const createMockResponse = (status: number, data?: any) => ({
|
|
@@ -246,7 +172,7 @@ describe('薪资管理集成测试', () => {
|
|
|
expect(screen.getByText('管理各地区薪资水平,支持基本工资、津贴、保险、公积金等计算')).toBeInTheDocument();
|
|
expect(screen.getByText('管理各地区薪资水平,支持基本工资、津贴、保险、公积金等计算')).toBeInTheDocument();
|
|
|
|
|
|
|
|
// 检查搜索区域
|
|
// 检查搜索区域
|
|
|
- expect(screen.getByTestId('area-select')).toBeInTheDocument();
|
|
|
|
|
|
|
+ expect(screen.getByTestId('search-area-select')).toBeInTheDocument();
|
|
|
expect(screen.getByText('搜索')).toBeInTheDocument();
|
|
expect(screen.getByText('搜索')).toBeInTheDocument();
|
|
|
expect(screen.getByText('添加薪资')).toBeInTheDocument();
|
|
expect(screen.getByText('添加薪资')).toBeInTheDocument();
|
|
|
|
|
|
|
@@ -294,10 +220,10 @@ describe('薪资管理集成测试', () => {
|
|
|
it('应该支持区域搜索', async () => {
|
|
it('应该支持区域搜索', async () => {
|
|
|
renderComponent();
|
|
renderComponent();
|
|
|
|
|
|
|
|
- // 找到搜索区域的AreaSelect组件(第一个)
|
|
|
|
|
- const searchAreaSelect = screen.getAllByTestId('area-select')[0];
|
|
|
|
|
- const provinceSelect = within(searchAreaSelect).getByTestId('province-select');
|
|
|
|
|
- const citySelect = within(searchAreaSelect).getByTestId('city-select');
|
|
|
|
|
|
|
+ // 找到搜索区域的AreaSelect组件
|
|
|
|
|
+ const searchAreaSelect = screen.getByTestId('search-area-select');
|
|
|
|
|
+ // 注意:实际的AreaSelect组件没有province-select、city-select这些test ID
|
|
|
|
|
+ // 我们需要通过其他方式测试
|
|
|
|
|
|
|
|
// 选择省份
|
|
// 选择省份
|
|
|
fireEvent.change(provinceSelect, { target: { value: '110000' } });
|
|
fireEvent.change(provinceSelect, { target: { value: '110000' } });
|
|
@@ -507,4 +433,116 @@ describe('薪资管理集成测试', () => {
|
|
|
expect(requestData.basicSalary).toBe(5000);
|
|
expect(requestData.basicSalary).toBe(5000);
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
|
|
+ it('应该验证表单字段的错误消息(中文)', async () => {
|
|
|
|
|
+ renderComponent();
|
|
|
|
|
+
|
|
|
|
|
+ // 打开添加模态框
|
|
|
|
|
+ const addButton = screen.getByTestId('add-salary-button');
|
|
|
|
|
+ fireEvent.click(addButton);
|
|
|
|
|
+
|
|
|
|
|
+ await waitFor(() => {
|
|
|
|
|
+ const addSalaryTexts = screen.getAllByText('添加薪资');
|
|
|
|
|
+ expect(addSalaryTexts.length).toBeGreaterThanOrEqual(2);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 尝试提交空表单,应该显示验证错误
|
|
|
|
|
+ const submitButton = screen.getByRole('button', { name: /创建薪资/i });
|
|
|
|
|
+ fireEvent.click(submitButton);
|
|
|
|
|
+
|
|
|
|
|
+ // 等待验证错误显示
|
|
|
|
|
+ await waitFor(() => {
|
|
|
|
|
+ // 检查区域选择错误消息 - 省份和城市应该显示中文错误消息
|
|
|
|
|
+ // 注意:由于AreaSelect是mock的,验证错误可能不会直接显示在FormMessage中
|
|
|
|
|
+ // 但我们可以验证表单验证是否失败
|
|
|
|
|
+
|
|
|
|
|
+ // 检查基本工资的错误消息
|
|
|
|
|
+ const formMessages = screen.getAllByRole('alert');
|
|
|
|
|
+ expect(formMessages.length).toBeGreaterThan(0);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 现在填写区域但基本工资为0
|
|
|
|
|
+ const modalAreaSelect = screen.getAllByTestId('area-select')[1];
|
|
|
|
|
+ const provinceSelect = within(modalAreaSelect).getByTestId('province-select');
|
|
|
|
|
+ const citySelect = within(modalAreaSelect).getByTestId('city-select');
|
|
|
|
|
+
|
|
|
|
|
+ // 选择省份和城市
|
|
|
|
|
+ fireEvent.change(provinceSelect, { target: { value: '110000' } });
|
|
|
|
|
+ await waitFor(() => {
|
|
|
|
|
+ expect(citySelect).not.toBeDisabled();
|
|
|
|
|
+ });
|
|
|
|
|
+ fireEvent.change(citySelect, { target: { value: '110100' } });
|
|
|
|
|
+
|
|
|
|
|
+ // 设置基本工资为0
|
|
|
|
|
+ const basicSalaryInput = screen.getByLabelText('基本工资');
|
|
|
|
|
+ fireEvent.change(basicSalaryInput, { target: { value: '0' } });
|
|
|
|
|
+
|
|
|
|
|
+ // 再次提交,应该显示基本工资的错误消息
|
|
|
|
|
+ fireEvent.click(submitButton);
|
|
|
|
|
+
|
|
|
|
|
+ await waitFor(() => {
|
|
|
|
|
+ // 验证错误消息应该显示
|
|
|
|
|
+ const errorMessages = screen.getAllByText(/基本工资必须大于0|必须大于0/i);
|
|
|
|
|
+ expect(errorMessages.length).toBeGreaterThan(0);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 测试负数津贴
|
|
|
|
|
+ const allowanceInput = screen.getByLabelText('津贴补贴');
|
|
|
|
|
+ fireEvent.change(allowanceInput, { target: { value: '-100' } });
|
|
|
|
|
+ fireEvent.change(basicSalaryInput, { target: { value: '5000' } }); // 修复基本工资
|
|
|
|
|
+
|
|
|
|
|
+ fireEvent.click(submitButton);
|
|
|
|
|
+
|
|
|
|
|
+ await waitFor(() => {
|
|
|
|
|
+ // 验证津贴的错误消息
|
|
|
|
|
+ const allowanceErrors = screen.getAllByText(/津贴补贴不能为负数|不能为负数/i);
|
|
|
|
|
+ expect(allowanceErrors.length).toBeGreaterThan(0);
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('应该验证区县字段为可选(不显示必填标记)', async () => {
|
|
|
|
|
+ renderComponent();
|
|
|
|
|
+
|
|
|
|
|
+ // 打开添加模态框
|
|
|
|
|
+ const addButton = screen.getByTestId('add-salary-button');
|
|
|
|
|
+ fireEvent.click(addButton);
|
|
|
|
|
+
|
|
|
|
|
+ await waitFor(() => {
|
|
|
|
|
+ const addSalaryTexts = screen.getAllByText('添加薪资');
|
|
|
|
|
+ expect(addSalaryTexts.length).toBeGreaterThanOrEqual(2);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 在模态框中找到AreaSelect组件
|
|
|
|
|
+ const modalAreaSelect = screen.getAllByTestId('area-select')[1];
|
|
|
|
|
+
|
|
|
|
|
+ // 验证AreaSelect组件被调用时required=true
|
|
|
|
|
+ expect(modalAreaSelect).toHaveAttribute('data-required', 'true');
|
|
|
|
|
+
|
|
|
|
|
+ // 验证区县字段不为必填
|
|
|
|
|
+ const requiredStatus = within(modalAreaSelect).getByTestId('required-status');
|
|
|
|
|
+ expect(requiredStatus).toHaveTextContent('区县必填: 否');
|
|
|
|
|
+
|
|
|
|
|
+ // 选择省份和城市
|
|
|
|
|
+ const provinceSelect = within(modalAreaSelect).getByTestId('province-select');
|
|
|
|
|
+ const citySelect = within(modalAreaSelect).getByTestId('city-select');
|
|
|
|
|
+ const districtSelect = within(modalAreaSelect).getByTestId('district-select');
|
|
|
|
|
+
|
|
|
|
|
+ fireEvent.change(provinceSelect, { target: { value: '110000' } });
|
|
|
|
|
+
|
|
|
|
|
+ await waitFor(() => {
|
|
|
|
|
+ const updatedRequiredStatus = within(modalAreaSelect).getByTestId('required-status');
|
|
|
|
|
+ expect(updatedRequiredStatus).toHaveTextContent('城市必填: 是');
|
|
|
|
|
+ expect(updatedRequiredStatus).toHaveTextContent('区县必填: 否');
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ fireEvent.change(citySelect, { target: { value: '110100' } });
|
|
|
|
|
+
|
|
|
|
|
+ // 验证区县字段仍然不为必填,即使选择了城市
|
|
|
|
|
+ await waitFor(() => {
|
|
|
|
|
+ const finalRequiredStatus = within(modalAreaSelect).getByTestId('required-status');
|
|
|
|
|
+ expect(finalRequiredStatus).toHaveTextContent('区县必填: 否');
|
|
|
|
|
+ expect(districtSelect).not.toBeDisabled(); // 区县选择器应该启用
|
|
|
|
|
+ expect(districtSelect).toHaveValue(''); // 区县应该为空(可选)
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
});
|
|
});
|