| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- import { describe, it, expect, beforeEach } from 'vitest';
- import { testClient } from 'hono/testing';
- import {
- IntegrationTestDatabase,
- setupIntegrationDatabaseHooks,
- TestDataFactory
- } from '~/utils/server/integration-test-db';
- import { IntegrationTestAssertions } from '~/utils/server/integration-test-utils';
- import { routesRoutesExport } from '@/server/api';
- import { VehicleType, TravelMode } from '@/server/modules/routes/route.schema';
- // 设置集成测试钩子
- setupIntegrationDatabaseHooks()
- describe('用户端路线搜索API集成测试', () => {
- let client: ReturnType<typeof testClient<typeof routesRoutesExport>>['api']['v1'];
- beforeEach(async () => {
- // 创建测试客户端
- client = testClient(routesRoutesExport).api.v1;
- // 创建测试数据
- const dataSource = await IntegrationTestDatabase.getDataSource();
- if (!dataSource) throw new Error('Database not initialized');
- // 创建测试活动
- const activity1 = await TestDataFactory.createTestActivity(dataSource, {
- name: '测试活动1'
- });
- const activity2 = await TestDataFactory.createTestActivity(dataSource, {
- name: '测试活动2'
- });
- // 创建测试路线,覆盖所有组合查询场景
- // 大巴拼车路线
- await TestDataFactory.createTestRoute(dataSource, {
- name: '大巴拼车路线1',
- vehicleType: VehicleType.BUS,
- travelMode: TravelMode.CARPOOL,
- activityId: activity1.id,
- price: 100,
- availableSeats: 30
- });
- await TestDataFactory.createTestRoute(dataSource, {
- name: '大巴拼车路线2',
- vehicleType: VehicleType.BUS,
- travelMode: TravelMode.CARPOOL,
- activityId: activity2.id,
- price: 120,
- availableSeats: 25
- });
- // 商务车路线(拼车)
- await TestDataFactory.createTestRoute(dataSource, {
- name: '商务车拼车路线',
- vehicleType: VehicleType.BUSINESS,
- travelMode: TravelMode.CARPOOL,
- activityId: activity1.id,
- price: 200,
- availableSeats: 4
- });
- // 商务车路线(包车)
- await TestDataFactory.createTestRoute(dataSource, {
- name: '商务车包车路线',
- vehicleType: VehicleType.BUSINESS,
- travelMode: TravelMode.CHARTER,
- activityId: activity2.id,
- price: 500,
- availableSeats: 4
- });
- // 大巴包车路线
- await TestDataFactory.createTestRoute(dataSource, {
- name: '大巴包车路线',
- vehicleType: VehicleType.BUS,
- travelMode: TravelMode.CHARTER,
- activityId: activity1.id,
- price: 800,
- availableSeats: 40
- });
- // 中巴拼车路线(用于验证排除逻辑)
- await TestDataFactory.createTestRoute(dataSource, {
- name: '中巴拼车路线',
- vehicleType: VehicleType.MINIBUS,
- travelMode: TravelMode.CARPOOL,
- activityId: activity1.id,
- price: 150,
- availableSeats: 15
- });
- // 小车包车路线(用于验证排除逻辑)
- await TestDataFactory.createTestRoute(dataSource, {
- name: '小车包车路线',
- vehicleType: VehicleType.CAR,
- travelMode: TravelMode.CHARTER,
- activityId: activity2.id,
- price: 300,
- availableSeats: 3
- });
- });
- describe('组合查询逻辑测试', () => {
- it('应该正确查询大巴拼车组合', async () => {
- const response = await client.routes.search.$get({
- query: {
- vehicleType: 'bus',
- travelMode: 'carpool'
- }
- });
- IntegrationTestAssertions.expectStatus(response, 200);
- if (response.status === 200) {
- const responseData = await response.json();
- expect(responseData.success).toBe(true);
- expect(responseData.data.routes).toHaveLength(2);
- // 验证所有返回路线都是大巴拼车
- responseData.data.routes.forEach((route: any) => {
- expect(route.vehicleType).toBe(VehicleType.BUS);
- expect(route.travelMode).toBe(TravelMode.CARPOOL);
- });
- // 验证包含正确的路线
- const routeNames = responseData.data.routes.map((route: any) => route.name);
- expect(routeNames).toContain('大巴拼车路线1');
- expect(routeNames).toContain('大巴拼车路线2');
- // 验证不包含其他类型的路线
- expect(routeNames).not.toContain('商务车拼车路线');
- expect(routeNames).not.toContain('大巴包车路线');
- }
- });
- it('应该正确查询商务车组合(支持拼车和包车)', async () => {
- const response = await client.routes.search.$get({
- query: {
- vehicleType: 'business',
- travelMode: 'carpool,charter'
- }
- });
- IntegrationTestAssertions.expectStatus(response, 200);
- if (response.status === 200) {
- const responseData = await response.json();
- expect(responseData.success).toBe(true);
- expect(responseData.data.routes).toHaveLength(2);
- // 验证所有返回路线都是商务车
- responseData.data.routes.forEach((route: any) => {
- expect(route.vehicleType).toBe(VehicleType.BUSINESS);
- });
- // 验证包含商务车拼车和包车路线
- const routeNames = responseData.data.routes.map((route: any) => route.name);
- expect(routeNames).toContain('商务车拼车路线');
- expect(routeNames).toContain('商务车包车路线');
- // 验证不包含其他车型的路线
- expect(routeNames).not.toContain('大巴拼车路线1');
- expect(routeNames).not.toContain('中巴拼车路线');
- }
- });
- it('应该正确查询包车组合(支持大巴和商务车)', async () => {
- const response = await client.routes.search.$get({
- query: {
- vehicleType: 'bus,business',
- travelMode: 'charter'
- }
- });
- IntegrationTestAssertions.expectStatus(response, 200);
- if (response.status === 200) {
- const responseData = await response.json();
- expect(responseData.success).toBe(true);
- expect(responseData.data.routes).toHaveLength(2);
- // 验证所有返回路线都是包车
- responseData.data.routes.forEach((route: any) => {
- expect(route.travelMode).toBe(TravelMode.CHARTER);
- });
- // 验证包含大巴包车和商务车包车路线
- const routeNames = responseData.data.routes.map((route: any) => route.name);
- expect(routeNames).toContain('大巴包车路线');
- expect(routeNames).toContain('商务车包车路线');
- // 验证不包含拼车路线
- expect(routeNames).not.toContain('大巴拼车路线1');
- expect(routeNames).not.toContain('商务车拼车路线');
- }
- });
- it('应该支持多值车型参数查询', async () => {
- const response = await client.routes.search.$get({
- query: {
- vehicleType: 'bus,minibus',
- travelMode: 'carpool'
- }
- });
- IntegrationTestAssertions.expectStatus(response, 200);
- if (response.status === 200) {
- const responseData = await response.json();
- expect(responseData.success).toBe(true);
- // 验证包含大巴拼车和中巴拼车路线
- const routeNames = responseData.data.routes.map((route: any) => route.name);
- expect(routeNames).toContain('大巴拼车路线1');
- expect(routeNames).toContain('大巴拼车路线2');
- expect(routeNames).toContain('中巴拼车路线');
- // 验证不包含商务车和小车路线
- expect(routeNames).not.toContain('商务车拼车路线');
- expect(routeNames).not.toContain('小车包车路线');
- }
- });
- it('应该支持多值出行方式参数查询', async () => {
- const response = await client.routes.search.$get({
- query: {
- vehicleType: 'business',
- travelMode: 'carpool,charter'
- }
- });
- IntegrationTestAssertions.expectStatus(response, 200);
- if (response.status === 200) {
- const responseData = await response.json();
- expect(responseData.success).toBe(true);
- // 验证包含商务车拼车和包车路线
- const routeNames = responseData.data.routes.map((route: any) => route.name);
- expect(routeNames).toContain('商务车拼车路线');
- expect(routeNames).toContain('商务车包车路线');
- }
- });
- it('应该正确处理单个参数查询', async () => {
- // 只查询车型
- const response1 = await client.routes.search.$get({
- query: {
- vehicleType: 'bus'
- }
- });
- IntegrationTestAssertions.expectStatus(response1, 200);
- if (response1.status === 200) {
- const responseData = await response1.json();
- expect(responseData.success).toBe(true);
- // 验证包含所有大巴路线(拼车和包车)
- const routeNames = responseData.data.routes.map((route: any) => route.name);
- expect(routeNames).toContain('大巴拼车路线1');
- expect(routeNames).toContain('大巴拼车路线2');
- expect(routeNames).toContain('大巴包车路线');
- }
- // 只查询出行方式
- const response2 = await client.routes.search.$get({
- query: {
- travelMode: 'carpool'
- }
- });
- IntegrationTestAssertions.expectStatus(response2, 200);
- if (response2.status === 200) {
- const responseData = await response2.json();
- expect(responseData.success).toBe(true);
- // 验证包含所有拼车路线
- const routeNames = responseData.data.routes.map((route: any) => route.name);
- expect(routeNames).toContain('大巴拼车路线1');
- expect(routeNames).toContain('大巴拼车路线2');
- expect(routeNames).toContain('商务车拼车路线');
- expect(routeNames).toContain('中巴拼车路线');
- }
- });
- it('应该正确处理空参数查询', async () => {
- const response = await client.routes.search.$get({
- query: {}
- });
- IntegrationTestAssertions.expectStatus(response, 200);
- if (response.status === 200) {
- const responseData = await response.json();
- expect(responseData.success).toBe(true);
- // 验证返回所有路线
- expect(responseData.data.routes.length).toBeGreaterThan(0);
- }
- });
- it('应该正确处理无效参数', async () => {
- // 无效车型参数
- const response1 = await client.routes.search.$get({
- query: {
- vehicleType: 'invalid_vehicle'
- }
- });
- IntegrationTestAssertions.expectStatus(response1, 200);
- if (response1.status === 200) {
- const responseData = await response1.json();
- expect(responseData.success).toBe(true);
- // 无效参数应该被忽略,返回所有路线
- expect(responseData.data.routes.length).toBeGreaterThan(0);
- }
- // 无效出行方式参数
- const response2 = await client.routes.search.$get({
- query: {
- travelMode: 'invalid_mode'
- }
- });
- IntegrationTestAssertions.expectStatus(response2, 200);
- if (response2.status === 200) {
- const responseData = await response2.json();
- expect(responseData.success).toBe(true);
- // 无效参数应该被忽略,返回所有路线
- expect(responseData.data.routes.length).toBeGreaterThan(0);
- }
- });
- });
- describe('组合查询与其他筛选条件结合测试', () => {
- it('应该支持组合查询与价格筛选结合', async () => {
- const response = await client.routes.search.$get({
- query: {
- vehicleType: 'bus',
- travelMode: 'carpool',
- minPrice: '110',
- maxPrice: '130'
- }
- });
- IntegrationTestAssertions.expectStatus(response, 200);
- if (response.status === 200) {
- const responseData = await response.json();
- expect(responseData.success).toBe(true);
- // 验证只返回价格在110-130之间的大巴拼车路线
- const routeNames = responseData.data.routes.map((route: any) => route.name);
- expect(routeNames).toContain('大巴拼车路线2'); // 价格120
- expect(routeNames).not.toContain('大巴拼车路线1'); // 价格100
- // 验证价格范围
- responseData.data.routes.forEach((route: any) => {
- expect(route.price).toBeGreaterThanOrEqual(110);
- expect(route.price).toBeLessThanOrEqual(130);
- });
- }
- });
- it('应该支持组合查询与活动筛选结合', async () => {
- const dataSource = await IntegrationTestDatabase.getDataSource();
- if (!dataSource) throw new Error('Database not initialized');
- const activity = await TestDataFactory.createTestActivity(dataSource, {
- name: '特定活动'
- });
- // 为特定活动创建路线
- await TestDataFactory.createTestRoute(dataSource, {
- name: '特定活动大巴拼车路线',
- vehicleType: VehicleType.BUS,
- travelMode: TravelMode.CARPOOL,
- activityId: activity.id,
- price: 150
- });
- const response = await client.routes.search.$get({
- query: {
- vehicleType: 'bus',
- travelMode: 'carpool'
- }
- });
- IntegrationTestAssertions.expectStatus(response, 200);
- if (response.status === 200) {
- const responseData = await response.json();
- expect(responseData.success).toBe(true);
- // 验证包含特定活动的路线
- const routeNames = responseData.data.routes.map((route: any) => route.name);
- expect(routeNames).toContain('特定活动大巴拼车路线');
- }
- });
- });
- describe('分页和排序测试', () => {
- it('应该支持组合查询的分页', async () => {
- const response = await client.routes.search.$get({
- query: {
- vehicleType: 'bus',
- travelMode: 'carpool',
- page: '1',
- pageSize: '1'
- }
- });
- IntegrationTestAssertions.expectStatus(response, 200);
- if (response.status === 200) {
- const responseData = await response.json();
- expect(responseData.success).toBe(true);
- // 验证分页信息
- expect(responseData.data.pagination.page).toBe(1);
- expect(responseData.data.pagination.pageSize).toBe(1);
- expect(responseData.data.pagination.total).toBe(2);
- expect(responseData.data.pagination.totalPages).toBe(2);
- // 验证只返回1条路线
- expect(responseData.data.routes).toHaveLength(1);
- }
- });
- it('应该支持组合查询的价格排序', async () => {
- const response = await client.routes.search.$get({
- query: {
- vehicleType: 'bus',
- travelMode: 'carpool',
- sortBy: 'price',
- sortOrder: 'ASC'
- }
- });
- IntegrationTestAssertions.expectStatus(response, 200);
- if (response.status === 200) {
- const responseData = await response.json();
- expect(responseData.success).toBe(true);
- // 验证路线按价格升序排列
- const prices = responseData.data.routes.map((route: any) => route.price);
- expect(prices[0]).toBeLessThanOrEqual(prices[1]);
- }
- });
- });
- });
|