Преглед изворни кода

✅ test(agora-stt): 添加Agora STT组件集成测试

- 创建AgoraSTTComponent.integration.test.tsx测试文件
- 模拟UI组件和Lucide图标以支持组件测试
- 实现真实API集成测试,验证Token生成和格式
- 添加错误处理测试,验证缺少参数和无效类型情况
- 测试API认证保护机制和权限控制
- 添加配置状态检查,提示缺少真实Agora配置时跳过相关测试
- 验证Token有效期和时间戳格式正确性
- 测试不同Token类型(rtc/rtm)的生成逻辑
yourname пре 4 месеци
родитељ
комит
c9aa8a355b

+ 298 - 0
src/client/admin/components/agora-stt/__integration_tests__/AgoraSTTComponent.integration.test.tsx

@@ -0,0 +1,298 @@
+import { describe, test, expect, vi, beforeEach, afterEach } from 'vitest';
+import { testClient } from 'hono/testing';
+import { agoraApiRoutes } from '@/server/api';
+import { authMiddleware } from '@/server/middleware/auth.middleware';
+
+// Mock UI components
+vi.mock('@/client/components/ui/button', () => ({
+  Button: ({ children, onClick, disabled, variant, className }: any) => (
+    <button
+      onClick={onClick}
+      disabled={disabled}
+      data-variant={variant}
+      className={className}
+    >
+      {children}
+    </button>
+  )
+}));
+
+vi.mock('@/client/components/ui/card', () => ({
+  Card: ({ children, className }: any) => (
+    <div className={className}>{children}</div>
+  ),
+  CardHeader: ({ children }: any) => <div>{children}</div>,
+  CardTitle: ({ children }: any) => <h3>{children}</h3>,
+  CardDescription: ({ children }: any) => <p>{children}</p>,
+  CardContent: ({ children }: any) => <div>{children}</div>
+}));
+
+vi.mock('@/client/components/ui/badge', () => ({
+  Badge: ({ children, variant, className }: any) => (
+    <span data-variant={variant} className={className}>{children}</span>
+  )
+}));
+
+vi.mock('@/client/components/ui/alert', () => ({
+  Alert: ({ children }: any) => <div role="alert">{children}</div>,
+  AlertDescription: ({ children }: any) => <div>{children}</div>
+}));
+
+// Mock Lucide icons
+vi.mock('lucide-react', () => ({
+  Mic: () => <span>Mic</span>,
+  MicOff: () => <span>MicOff</span>,
+  Play: () => <span>Play</span>,
+  Square: () => <span>Square</span>,
+  Trash2: () => <span>Trash2</span>,
+  Wifi: () => <span>Wifi</span>,
+  WifiOff: () => <span>WifiOff</span>
+}));
+
+// Mock auth middleware
+vi.mock('@/server/middleware/auth.middleware', () => ({
+  authMiddleware: vi.fn()
+}));
+
+// Mock用户数据
+const mockUser = {
+  id: 1,
+  username: 'testuser',
+  password: 'password123',
+  phone: null,
+  email: 'test@example.com',
+  nickname: null,
+  name: null,
+  avatarFileId: null,
+  avatarFile: null,
+  isDisabled: 0,
+  isDeleted: 0,
+  roles: [],
+  createdAt: new Date(),
+  updatedAt: new Date()
+};
+
+// 只在有真实Agora配置时运行这些测试
+const hasRealAgoraConfig = process.env.AGORA_APP_ID && process.env.AGORA_APP_SECRET;
+
+
+describe('AgoraSTTComponent 真实API集成测试', () => {
+  let client: ReturnType<typeof testClient<typeof agoraApiRoutes>>['api']['v1'];
+
+  beforeEach(() => {
+    // Mock auth middleware
+    vi.mocked(authMiddleware).mockImplementation(async (c, next) => {
+      const authHeader = c.req.header('Authorization');
+      if (!authHeader) {
+        return c.json({ message: 'Authorization header missing' }, 401);
+      }
+      c.set('user', mockUser);
+      await next();
+    });
+
+    // 创建测试客户端
+    client = testClient(agoraApiRoutes).api.v1;
+
+    // 设置环境变量
+    process.env.AGORA_APP_ID = process.env.AGORA_APP_ID || 'test-app-id';
+    process.env.AGORA_APP_SECRET = process.env.AGORA_APP_SECRET || 'test-app-secret';
+    process.env.AGORA_TOKEN_EXPIRY = '3600';
+  });
+
+  afterEach(() => {
+    vi.clearAllMocks();
+  });
+
+  // 跳过测试如果没有真实配置
+  const runIfRealConfig = hasRealAgoraConfig ? test : test.skip;
+
+  runIfRealConfig('组件应该能够调用真实Token API', async () => {
+    // 模拟组件调用Token API
+    const response = await client.agora.token.$get({
+      query: { type: 'rtc', channel: 'test-channel' }
+    },
+    {
+      headers: {
+        'Authorization': 'Bearer test-token'
+      }
+    });
+
+    expect(response.status).toBe(200);
+
+    const data = await response.json();
+
+    // 验证真实Token格式
+    if ('token' in data) {
+      expect(data).toHaveProperty('token');
+      expect(data).toHaveProperty('type');
+      expect(data).toHaveProperty('expiresAt');
+      expect(data).toHaveProperty('expiresIn');
+      expect(data).toHaveProperty('generatedAt');
+
+      // 验证Token类型
+      expect(data.type).toBe('rtc');
+
+      // 验证Token格式
+      expect(data.token).toMatch(/^[A-Za-z0-9+/=]+$/);
+      expect(data.token.length).toBeGreaterThan(20);
+
+      // 验证时间戳格式
+      expect(data.expiresAt).toBeGreaterThan(data.generatedAt);
+      expect(data.expiresIn).toBeGreaterThan(0);
+      expect(data.expiresAt - data.generatedAt).toBe(data.expiresIn);
+    }
+  });
+
+  runIfRealConfig('Token API错误处理测试', async () => {
+    // 测试缺少必需参数
+    const response = await client.agora.token.$get({
+      query: { type: 'rtc' } // 缺少channel参数
+    },
+    {
+      headers: {
+        'Authorization': 'Bearer test-token'
+      }
+    });
+
+    expect(response.status).toBe(400);
+
+    const errorData = await response.json();
+
+    if ('message' in errorData) {
+      expect(errorData.message).toContain('RTC Token需要提供channel参数');
+    }
+  });
+
+  runIfRealConfig('不同Token类型测试', async () => {
+    // 测试RTC Token
+    const rtcResponse = await client.agora.token.$get({
+      query: { type: 'rtc', channel: 'test-channel-rtc' }
+    },
+    {
+      headers: {
+        'Authorization': 'Bearer test-token'
+      }
+    });
+
+    expect(rtcResponse.status).toBe(200);
+
+    const rtcData = await rtcResponse.json();
+    if ('token' in rtcData) {
+      expect(rtcData.type).toBe('rtc');
+    }
+
+    // 测试RTM Token
+    const rtmResponse = await client.agora.token.$get({
+      query: { type: 'rtm', userId: 'test-user-rtm' }
+    },
+    {
+      headers: {
+        'Authorization': 'Bearer test-token'
+      }
+    });
+
+    expect(rtmResponse.status).toBe(200);
+
+    const rtmData = await rtmResponse.json();
+    if ('token' in rtmData) {
+      expect(rtmData.type).toBe('rtm');
+    }
+  });
+
+  runIfRealConfig('Token有效期验证', async () => {
+    const response = await client.agora.token.$get({
+      query: { type: 'rtc', channel: 'test-channel-validity' }
+    },
+    {
+      headers: {
+        'Authorization': 'Bearer test-token'
+      }
+    });
+
+    expect(response.status).toBe(200);
+
+    const data = await response.json();
+
+    if ('token' in data) {
+      // 验证Token在有效期内
+      const currentTime = Math.floor(Date.now() / 1000);
+      expect(data.expiresAt).toBeGreaterThan(currentTime);
+      expect(data.expiresAt).toBeLessThanOrEqual(currentTime + 3600); // 默认1小时有效期
+
+      // 验证生成时间在当前时间之前或等于
+      expect(data.generatedAt).toBeLessThanOrEqual(currentTime);
+    }
+  });
+
+  // 组件集成测试 - 模拟组件使用真实API
+  runIfRealConfig('组件集成Token获取流程', async () => {
+    // 模拟组件调用Token API的过程
+    const fetchToken = async (type: 'rtc' | 'rtm', channel?: string, userId?: string) => {
+      const query: any = { type };
+
+      if (type === 'rtc' && channel) {
+        query.channel = channel;
+      } else if (type === 'rtm' && userId) {
+        query.userId = userId;
+      }
+
+      const response = await client.agora.token.$get({ query }, {
+        headers: { 'Authorization': 'Bearer test-token' }
+      });
+
+      if (!response.ok) {
+        throw new Error(`Token API returned ${response.status}`);
+      }
+
+      const data = await response.json();
+      return data.token;
+    };
+
+    // 测试组件会调用的Token获取
+    const token = await fetchToken('rtc', 'test-integration-channel');
+    expect(token).toBeTruthy();
+    expect(typeof token).toBe('string');
+  });
+
+  // 总是运行的测试(不依赖真实配置)
+  test('API认证保护测试', async () => {
+    // 测试未认证访问
+    const response = await client.agora.token.$get({
+      query: { type: 'rtc', channel: 'test-channel' }
+    });
+
+    expect(response.status).toBe(401);
+
+    const errorData = await response.json();
+    if ('message' in errorData) {
+      expect(errorData.message).toContain('Authorization header missing');
+    }
+  });
+
+  test('无效Token类型参数验证', async () => {
+    const response = await client.agora.token.$get({
+      query: { type: 'invalid-type' as any, channel: 'test-channel' }
+    },
+    {
+      headers: {
+        'Authorization': 'Bearer test-token'
+      }
+    });
+
+    // 由于Zod验证,应该返回400错误
+    expect(response.status).toBe(400);
+  });
+});
+
+// 配置状态检查
+describe('AgoraSTTComponent 配置状态检查', () => {
+  test('检查Agora配置状态', () => {
+    if (!hasRealAgoraConfig) {
+      console.warn('⚠️  没有真实的Agora配置,前端真实API集成测试将被跳过');
+      console.warn('   请设置AGORA_APP_ID和AGORA_APP_SECRET环境变量来启用真实API测试');
+    }
+
+    // 这个测试总是通过,用于提供信息
+    expect(true).toBe(true);
+  });
+});