import React from 'react' import { render, fireEvent, waitFor } from '@testing-library/react' import { LocationSearch } from '../../src/components/LocationSearch' // Mock API调用 jest.mock('../../src/api', () => ({ locationClient: { $get: jest.fn().mockImplementation(({ query }) => { if (query.keyword === '北京') { return Promise.resolve({ status: 200, json: jest.fn().mockResolvedValue([ { id: 1, name: '北京首都国际机场', province: '北京市', city: '北京市', district: '朝阳区', address: '北京市朝阳区首都机场路' }, { id: 2, name: '北京南站', province: '北京市', city: '北京市', district: '丰台区', address: '北京市丰台区永外大街12号' } ]) }) } if (query.keyword === '上海') { return Promise.resolve({ status: 200, json: jest.fn().mockResolvedValue([ { id: 3, name: '上海虹桥机场', province: '上海市', city: '上海市', district: '长宁区', address: '上海市长宁区虹桥路2550号' } ]) }) } return Promise.resolve({ status: 200, json: jest.fn().mockResolvedValue([]) }) }) } })) describe('LocationSearch', () => { beforeEach(() => { jest.clearAllMocks() }) it('应该正确渲染初始状态', () => { const { getByPlaceholderText } = render() expect(getByPlaceholderText('搜索地点')).toBeTruthy() }) it('应该显示自定义占位符', () => { const { getByPlaceholderText } = render( ) expect(getByPlaceholderText('请输入地点名称')).toBeTruthy() }) it('应该处理输入变化并显示搜索结果', async () => { const { getByPlaceholderText, getByText } = render() const input = getByPlaceholderText('搜索地点') fireEvent.input(input, { target: { value: '北京' } }) await waitFor(() => { expect(getByText('北京首都国际机场')).toBeTruthy() expect(getByText('北京南站')).toBeTruthy() }) }) it('应该正确选择地点并触发onChange', async () => { const mockOnChange = jest.fn() const { getByPlaceholderText, getByText } = render( ) const input = getByPlaceholderText('搜索地点') fireEvent.input(input, { target: { value: '北京' } }) await waitFor(() => { expect(getByText('北京首都国际机场')).toBeTruthy() }) const locationItem = getByText('北京首都国际机场') fireEvent.click(locationItem) expect(mockOnChange).toHaveBeenCalledWith({ id: 1, name: '北京首都国际机场', province: '北京市', city: '北京市', district: '朝阳区', address: '北京市朝阳区首都机场路' }) }) it('应该支持地区筛选', async () => { const { getByPlaceholderText } = render( ) const input = getByPlaceholderText('搜索地点') fireEvent.input(input, { target: { value: '北京' } }) await waitFor(() => { // 验证API调用时传递了地区筛选参数 const locationClient = require('../../src/api').locationClient expect(locationClient.$get).toHaveBeenCalledWith({ query: { keyword: '北京', provinceId: 1, cityId: 11, districtId: 111 } }) }) }) it('应该处理清除操作', async () => { const mockOnChange = jest.fn() const { getByPlaceholderText, getByText } = render( ) const input = getByPlaceholderText('搜索地点') fireEvent.input(input, { target: { value: '北京' } }) await waitFor(() => { expect(getByText('北京首都国际机场')).toBeTruthy() }) // 选择地点 const locationItem = getByText('北京首都国际机场') fireEvent.click(locationItem) // 清除输入 const clearButton = getByText('×') fireEvent.click(clearButton) expect(mockOnChange).toHaveBeenCalledWith(null) }) it('应该显示当前选择的地点', () => { const selectedLocation = { id: 1, name: '北京首都国际机场', province: '北京市', city: '北京市', district: '朝阳区', address: '北京市朝阳区首都机场路' } const { getByText } = render( ) expect(getByText('已选择: 北京首都国际机场 · 朝阳区 · 北京市 · 北京市')).toBeTruthy() }) it('应该处理空搜索结果', async () => { const { getByPlaceholderText, getByText } = render() const input = getByPlaceholderText('搜索地点') fireEvent.input(input, { target: { value: '不存在的城市' } }) await waitFor(() => { expect(getByText('未找到相关地点')).toBeTruthy() }) }) it('应该处理防抖搜索', async () => { jest.useFakeTimers() const { getByPlaceholderText } = render() const input = getByPlaceholderText('搜索地点') // 快速输入多个字符 fireEvent.input(input, { target: { value: '北' } }) fireEvent.input(input, { target: { value: '北京' } }) fireEvent.input(input, { target: { value: '北京市' } }) // 验证API只被调用一次(防抖) const locationClient = require('../../src/api').locationClient expect(locationClient.$get).not.toHaveBeenCalled() // 快进防抖时间 jest.advanceTimersByTime(300) await waitFor(() => { expect(locationClient.$get).toHaveBeenCalledTimes(1) expect(locationClient.$get).toHaveBeenCalledWith({ query: { keyword: '北京市' } }) }) jest.useRealTimers() }) })