| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- import { test, expect } from '@playwright/test';
- /**
- * E2E测试:统一广告API兼容性验证
- *
- * 目的:验证统一广告模块替换后,用户端API路径和响应结构保持100%兼容
- * 确保:小程序端无需任何修改即可正常工作
- *
- * API端点映射:
- * - /api/v1/advertisements → unifiedAdvertisementRoutes (用户端)
- * - /api/v1/advertisement-types → unifiedAdvertisementTypeRoutes (用户端)
- * - /api/v1/admin/unified-advertisements → unifiedAdvertisementAdminRoutes (管理员端)
- * - /api/v1/admin/unified-advertisement-types → unifiedAdvertisementTypeAdminRoutes (管理员端)
- */
- test.describe('统一广告API兼容性测试', () => {
- const baseUrl = process.env.API_BASE_URL || 'http://localhost:8080';
- test.describe('用户端广告API (小程序使用)', () => {
- test('GET /api/v1/advertisements - 获取广告列表', async ({ request }) => {
- const response = await request.get(`${baseUrl}/api/v1/advertisements`);
- // 验证响应状态
- expect(response.status()).toBe(200);
- const data = await response.json();
- // 验证响应结构包含广告列表或空数组
- expect(Array.isArray(data)).toBeTruthy();
- // 如果有数据,验证字段结构
- if (data.length > 0) {
- const ad = data[0];
- expect(ad).toHaveProperty('id');
- expect(ad).toHaveProperty('title');
- expect(ad).toHaveProperty('imageUrl');
- expect(ad).toHaveProperty('linkUrl');
- expect(ad).toHaveProperty('position');
- expect(ad).toHaveProperty('status');
- }
- });
- test('GET /api/v1/advertisements?position=home - 获取指定位置广告', async ({ request }) => {
- const response = await request.get(`${baseUrl}/api/v1/advertisements?position=home`);
- expect(response.status()).toBe(200);
- const data = await response.json();
- expect(Array.isArray(data)).toBeTruthy();
- // 验证返回的ads都是home位置
- if (data.length > 0) {
- data.forEach((ad: any) => {
- expect(ad.position).toBe('home');
- });
- }
- });
- test('GET /api/v1/advertisements/:id - 获取广告详情', async ({ request }) => {
- // 先获取列表,找一个有效的ID
- const listResponse = await request.get(`${baseUrl}/api/v1/advertisements`);
- const listData = await listResponse.json();
- if (listData.length > 0) {
- const adId = listData[0].id;
- const response = await request.get(`${baseUrl}/api/v1/advertisements/${adId}`);
- expect(response.status()).toBe(200);
- const data = await response.json();
- expect(data).toHaveProperty('id', adId);
- expect(data).toHaveProperty('title');
- expect(data).toHaveProperty('imageUrl');
- expect(data).toHaveProperty('linkUrl');
- expect(data).toHaveProperty('position');
- expect(data).toHaveProperty('status');
- } else {
- test.skip(); // 没有广告数据时跳过
- }
- });
- test('GET /api/v1/advertisement-types - 获取广告类型列表', async ({ request }) => {
- const response = await request.get(`${baseUrl}/api/v1/advertisement-types`);
- expect(response.status()).toBe(200);
- const data = await response.json();
- expect(Array.isArray(data)).toBeTruthy();
- // 验证响应结构
- if (data.length > 0) {
- const adType = data[0];
- expect(adType).toHaveProperty('id');
- expect(adType).toHaveProperty('typeName');
- expect(adType).toHaveProperty('description');
- expect(adType).toHaveProperty('status');
- }
- });
- test('验证响应字段类型正确性', async ({ request }) => {
- const response = await request.get(`${baseUrl}/api/v1/advertisements`);
- const data = await response.json();
- if (data.length > 0) {
- const ad = data[0];
- expect(typeof ad.id).toBe('number');
- expect(typeof ad.title).toBe('string');
- expect(typeof ad.imageUrl).toBe('string');
- expect(typeof ad.linkUrl).toBe('string');
- expect(typeof ad.position).toBe('string');
- expect(typeof ad.status).toBe('number');
- }
- });
- });
- test.describe('管理员广告API (租户后台使用)', () => {
- let authToken: string;
- test.beforeAll(async ({ request }) => {
- // 使用超级管理员账号登录获取token
- const loginResponse = await request.post(`${baseUrl}/api/v1/auth/login`, {
- data: {
- username: 'admin',
- password: 'admin123'
- }
- });
- if (loginResponse.status() === 200) {
- const loginData = await loginResponse.json();
- authToken = loginData.token || loginData.access_token;
- }
- });
- test('GET /api/v1/admin/unified-advertisements - 管理员获取广告列表', async ({ request }) => {
- if (!authToken) {
- test.skip(); // 未登录则跳过
- }
- const response = await request.get(`${baseUrl}/api/v1/admin/unified-advertisements`, {
- headers: {
- 'Authorization': `Bearer ${authToken}`
- }
- });
- // 管理员API应该返回200或401(取决于权限配置)
- expect([200, 401, 403]).toContain(response.status());
- if (response.status() === 200) {
- const data = await response.json();
- expect(Array.isArray(data)).toBeTruthy();
- }
- });
- test('GET /api/v1/admin/unified-advertisement-types - 管理员获取广告类型列表', async ({ request }) => {
- if (!authToken) {
- test.skip(); // 未登录则跳过
- }
- const response = await request.get(`${baseUrl}/api/v1/admin/unified-advertisement-types`, {
- headers: {
- 'Authorization': `Bearer ${authToken}`
- }
- });
- expect([200, 401, 403]).toContain(response.status());
- if (response.status() === 200) {
- const data = await response.json();
- expect(Array.isArray(data)).toBeTruthy();
- }
- });
- });
- test.describe('API路径兼容性验证', () => {
- test('验证所有用户端广告API端点可访问', async ({ request }) => {
- const endpoints = [
- '/api/v1/advertisements',
- '/api/v1/advertisement-types'
- ];
- for (const endpoint of endpoints) {
- const response = await request.get(`${baseUrl}${endpoint}`);
- expect(response.status(), `端点 ${endpoint} 应该返回200`).toBe(200);
- }
- });
- test('验证管理员API端点存在', async ({ request }) => {
- const endpoints = [
- '/api/v1/admin/unified-advertisements',
- '/api/v1/admin/unified-advertisement-types'
- ];
- for (const endpoint of endpoints) {
- const response = await request.get(`${baseUrl}${endpoint}`);
- // 管理员API需要认证,所以期望401或403,而不是404
- expect([401, 403], `端点 ${endpoint} 应该存在但需要认证`).toContain(response.status());
- }
- });
- });
- test.describe('响应数据结构兼容性', () => {
- test('广告列表响应结构与原模块一致', async ({ request }) => {
- const response = await request.get(`${baseUrl}/api/v1/advertisements`);
- const data = await response.json();
- if (data.length > 0) {
- const ad = data[0];
- // 验证必填字段存在
- expect(ad).toHaveProperty('id');
- expect(ad).toHaveProperty('title');
- expect(ad).toHaveProperty('imageUrl');
- expect(ad).toHaveProperty('linkUrl');
- expect(ad).toHaveProperty('position');
- // 验证可选字段存在
- expect(ad).toHaveProperty('description');
- expect(ad).toHaveProperty('status');
- expect(ad).toHaveProperty('sortOrder');
- }
- });
- test('广告类型响应结构与原模块一致', async ({ request }) => {
- const response = await request.get(`${baseUrl}/api/v1/advertisement-types`);
- const data = await response.json();
- if (data.length > 0) {
- const adType = data[0];
- // 验证必填字段存在
- expect(adType).toHaveProperty('id');
- expect(adType).toHaveProperty('typeName');
- expect(adType).toHaveProperty('description');
- expect(adType).toHaveProperty('status');
- }
- });
- });
- });
|