| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- import { describe, it, expect, vi, beforeEach } from 'vitest';
- import { render, screen, fireEvent, waitFor, act } from '@testing-library/react';
- import { useForm, FormProvider } from 'react-hook-form';
- import { zodResolver } from '@hookform/resolvers/zod';
- import { z } from 'zod';
- import { AreaSelectForm } from '../../src/components/AreaSelectForm';
- import { Button } from '@d8d/shared-ui-components/components/ui/button';
- import { Form } from '@d8d/shared-ui-components/components/ui/form';
- // 测试用的schema
- const TestSchema = z.object({
- province: z.string().min(1, '省份不能为空'),
- city: z.string().min(1, '城市不能为空'),
- district: z.string().optional(),
- });
- type TestFormData = z.infer<typeof TestSchema>;
- // Mock AreaSelect 组件
- vi.mock('../../src/components/AreaSelect', () => ({
- AreaSelect: vi.fn(({ value, onChange, disabled, required }) => {
- return (
- <div data-testid="area-select">
- <select
- data-testid="province-select"
- value={value?.provinceId || ''}
- onChange={(e) => {
- const newValue = {
- ...value,
- provinceId: e.target.value ? Number(e.target.value) : undefined,
- };
- onChange(newValue);
- }}
- disabled={disabled}
- // 移除 required 属性,让 react-hook-form 处理验证
- >
- <option value="">选择省份</option>
- <option value="1">北京市</option>
- <option value="2">上海市</option>
- </select>
- <select
- data-testid="city-select"
- value={value?.cityId || ''}
- onChange={(e) => {
- const newValue = {
- ...value,
- cityId: e.target.value ? Number(e.target.value) : undefined,
- };
- onChange(newValue);
- }}
- disabled={disabled}
- // 移除 required 属性,让 react-hook-form 处理验证
- >
- <option value="">选择城市</option>
- <option value="3">北京市</option>
- <option value="4">上海市</option>
- </select>
- <select
- data-testid="district-select"
- value={value?.districtId || ''}
- onChange={(e) => {
- const newValue = {
- ...value,
- districtId: e.target.value ? Number(e.target.value) : undefined,
- };
- onChange(newValue);
- }}
- disabled={disabled}
- >
- <option value="">选择区县</option>
- <option value="5">东城区</option>
- <option value="6">黄浦区</option>
- </select>
- </div>
- );
- }),
- }));
- // 测试组件
- const TestForm = () => {
- const form = useForm<TestFormData>({
- resolver: zodResolver(TestSchema),
- defaultValues: {
- province: '',
- city: '',
- district: '',
- },
- mode: 'onSubmit', // 使用onSubmit模式,这是默认值
- });
- const onSubmit = vi.fn();
- return (
- <FormProvider {...form}>
- <Form {...form}>
- <form onSubmit={form.handleSubmit(onSubmit)}>
- <AreaSelectForm<TestFormData>
- provinceName="province"
- cityName="city"
- districtName="district"
- label="地区选择"
- required={true}
- control={form.control}
- />
- <Button type="submit" data-testid="submit-button">
- 提交
- </Button>
- </form>
- </Form>
- </FormProvider>
- );
- };
- describe('AreaSelectForm 集成测试', () => {
- beforeEach(() => {
- vi.clearAllMocks();
- });
- it('应该正确渲染AreaSelectForm组件', () => {
- render(<TestForm />);
- expect(screen.getByText('地区选择')).toBeInTheDocument();
- // 检查是否包含必填标记(星号)
- const label = screen.getByText('地区选择');
- expect(label.parentElement).toContainHTML('*');
- expect(screen.getByTestId('area-select')).toBeInTheDocument();
- });
- it('应该显示省份和城市的验证错误当表单提交时', async () => {
- let formRef: any;
- const TestFormWithRef = () => {
- const form = useForm<TestFormData>({
- resolver: zodResolver(TestSchema),
- defaultValues: {
- province: '',
- city: '',
- district: '',
- },
- mode: 'onSubmit',
- });
- formRef = form;
- const onSubmit = vi.fn();
- return (
- <FormProvider {...form}>
- <Form {...form}>
- <form onSubmit={form.handleSubmit(onSubmit)}>
- <AreaSelectForm<TestFormData>
- provinceName="province"
- cityName="city"
- districtName="district"
- label="地区选择"
- required={true}
- control={form.control}
- />
- <Button type="submit" data-testid="submit-button">
- 提交
- </Button>
- </form>
- </Form>
- </FormProvider>
- );
- };
- render(<TestFormWithRef />);
- // 初始状态不应该有验证错误
- expect(screen.queryByText('省份不能为空')).not.toBeInTheDocument();
- expect(screen.queryByText('城市不能为空')).not.toBeInTheDocument();
- // 提交表单(不选择任何省份和城市)
- const submitButton = screen.getByTestId('submit-button');
- await act(async () => {
- fireEvent.click(submitButton);
- });
- // 等待一下,让验证完成
- await new Promise(resolve => setTimeout(resolve, 100));
- // 等待验证错误显示
- await waitFor(() => {
- expect(screen.getByText('省份不能为空')).toBeInTheDocument();
- expect(screen.getByText('城市不能为空')).toBeInTheDocument();
- }, { timeout: 3000 });
- });
- it('应该正确更新表单字段值当选择省份和城市时', async () => {
- render(<TestForm />);
- // 选择省份
- const provinceSelect = screen.getByTestId('province-select');
- fireEvent.change(provinceSelect, { target: { value: '1' } });
- // 选择城市
- const citySelect = screen.getByTestId('city-select');
- fireEvent.change(citySelect, { target: { value: '3' } });
- // 提交表单
- const submitButton = screen.getByTestId('submit-button');
- fireEvent.click(submitButton);
- // 不应该有验证错误
- await waitFor(() => {
- expect(screen.queryByText('省份不能为空')).not.toBeInTheDocument();
- expect(screen.queryByText('城市不能为空')).not.toBeInTheDocument();
- });
- });
- it('应该显示验证错误当只选择省份不选择城市时', async () => {
- render(<TestForm />);
- // 只选择省份
- const provinceSelect = screen.getByTestId('province-select');
- fireEvent.change(provinceSelect, { target: { value: '1' } });
- // 提交表单
- const submitButton = screen.getByTestId('submit-button');
- fireEvent.click(submitButton);
- // 应该只有城市验证错误
- await waitFor(() => {
- expect(screen.queryByText('省份不能为空')).not.toBeInTheDocument();
- expect(screen.getByText('城市不能为空')).toBeInTheDocument();
- });
- });
- it('应该显示验证错误当只选择城市不选择省份时', async () => {
- render(<TestForm />);
- // 只选择城市
- const citySelect = screen.getByTestId('city-select');
- fireEvent.change(citySelect, { target: { value: '3' } });
- // 提交表单
- const submitButton = screen.getByTestId('submit-button');
- fireEvent.click(submitButton);
- // 应该只有省份验证错误
- await waitFor(() => {
- expect(screen.getByText('省份不能为空')).toBeInTheDocument();
- expect(screen.queryByText('城市不能为空')).not.toBeInTheDocument();
- });
- });
- it('应该正确处理区县字段(可选)', async () => {
- render(<TestForm />);
- // 选择省份和城市
- const provinceSelect = screen.getByTestId('province-select');
- const citySelect = screen.getByTestId('city-select');
- fireEvent.change(provinceSelect, { target: { value: '1' } });
- fireEvent.change(citySelect, { target: { value: '3' } });
- // 选择区县(可选)
- const districtSelect = screen.getByTestId('district-select');
- fireEvent.change(districtSelect, { target: { value: '5' } });
- // 提交表单
- const submitButton = screen.getByTestId('submit-button');
- fireEvent.click(submitButton);
- // 不应该有验证错误
- await waitFor(() => {
- expect(screen.queryByText('省份不能为空')).not.toBeInTheDocument();
- expect(screen.queryByText('城市不能为空')).not.toBeInTheDocument();
- });
- });
- it('应该支持禁用状态', () => {
- const DisabledTestForm = () => {
- const form = useForm<TestFormData>({
- resolver: zodResolver(TestSchema),
- defaultValues: {
- province: '',
- city: '',
- district: '',
- },
- });
- return (
- <FormProvider {...form}>
- <Form {...form}>
- <AreaSelectForm<TestFormData>
- provinceName="province"
- cityName="city"
- districtName="district"
- label="地区选择"
- required={true}
- disabled={true}
- control={form.control}
- />
- </Form>
- </FormProvider>
- );
- };
- render(<DisabledTestForm />);
- const provinceSelect = screen.getByTestId('province-select');
- const citySelect = screen.getByTestId('city-select');
- const districtSelect = screen.getByTestId('district-select');
- expect(provinceSelect).toBeDisabled();
- expect(citySelect).toBeDisabled();
- expect(districtSelect).toBeDisabled();
- });
- });
|