agora-stt.spec.ts 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. import { test, expect } from '../../utils/test-setup';
  2. import testUsers from '../../fixtures/test-users.json' with { type: 'json' };
  3. test.describe('Agora实时语音转录功能', () => {
  4. test.beforeEach(async ({ adminLoginPage, agoraSTTPage }) => {
  5. // 以管理员身份登录
  6. await adminLoginPage.goto();
  7. await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
  8. // 直接访问Agora STT页面
  9. await agoraSTTPage.goto();
  10. });
  11. test('Agora STT页面加载', async ({ agoraSTTPage }) => {
  12. await agoraSTTPage.expectToBeVisible();
  13. });
  14. test('组件初始状态验证', async ({ agoraSTTPage }) => {
  15. // 验证初始状态
  16. await expect(agoraSTTPage.joinChannelButton).toBeVisible();
  17. await expect(agoraSTTPage.leaveChannelButton).not.toBeVisible();
  18. await expect(agoraSTTPage.startRecordingButton).not.toBeVisible();
  19. await expect(agoraSTTPage.stopRecordingButton).not.toBeVisible();
  20. await expect(agoraSTTPage.clearTranscriptionsButton).not.toBeVisible();
  21. // 验证状态徽章
  22. const connectionStatus = await agoraSTTPage.getConnectionStatus();
  23. expect(connectionStatus).toBe('未连接');
  24. const recordingStatus = await agoraSTTPage.getRecordingStatus();
  25. expect(recordingStatus).toBe('未录制');
  26. const microphoneStatus = await agoraSTTPage.getMicrophonePermissionStatus();
  27. expect(microphoneStatus).toMatch(/麦克风权限|麦克风已授权|麦克风被拒绝/);
  28. const transcriptionCount = await agoraSTTPage.getTranscriptionCount();
  29. expect(transcriptionCount).toBe(0);
  30. // 验证使用说明显示
  31. await expect(agoraSTTPage.usageInstructions).toBeVisible();
  32. });
  33. test('加入和离开频道功能', async ({ agoraSTTPage }) => {
  34. // 加入频道
  35. await agoraSTTPage.joinChannel();
  36. // 验证连接状态更新
  37. await expect(agoraSTTPage.leaveChannelButton).toBeVisible();
  38. await expect(agoraSTTPage.startRecordingButton).toBeVisible();
  39. await expect(agoraSTTPage.clearTranscriptionsButton).toBeVisible();
  40. await expect(agoraSTTPage.joinChannelButton).not.toBeVisible();
  41. // 离开频道
  42. await agoraSTTPage.leaveChannel();
  43. // 验证回到初始状态
  44. await expect(agoraSTTPage.joinChannelButton).toBeVisible();
  45. await expect(agoraSTTPage.leaveChannelButton).not.toBeVisible();
  46. await expect(agoraSTTPage.startRecordingButton).not.toBeVisible();
  47. await expect(agoraSTTPage.clearTranscriptionsButton).not.toBeVisible();
  48. });
  49. test('麦克风权限申请流程', async ({ agoraSTTPage, page }) => {
  50. // 加入频道
  51. await agoraSTTPage.joinChannel();
  52. // 模拟麦克风权限申请
  53. // 注意:在测试环境中,我们无法实际授予麦克风权限
  54. // 但可以验证按钮状态和错误处理
  55. const initialMicrophoneStatus = await agoraSTTPage.getMicrophonePermissionStatus();
  56. // 尝试开始录音
  57. await agoraSTTPage.startRecording();
  58. // 验证录制状态更新
  59. const recordingStatus = await agoraSTTPage.getRecordingStatus();
  60. expect(recordingStatus).toBe('录制中');
  61. // 停止录音
  62. await agoraSTTPage.stopRecording();
  63. // 验证录制状态恢复
  64. const stoppedRecordingStatus = await agoraSTTPage.getRecordingStatus();
  65. expect(stoppedRecordingStatus).toBe('未录制');
  66. });
  67. test('转录结果显示功能', async ({ agoraSTTPage }) => {
  68. // 加入频道
  69. await agoraSTTPage.joinChannel();
  70. // 开始录音
  71. await agoraSTTPage.startRecording();
  72. // 等待一小段时间模拟录音过程
  73. await agoraSTTPage.page.waitForTimeout(2000);
  74. // 停止录音
  75. await agoraSTTPage.stopRecording();
  76. // 验证转录计数可能增加(在模拟环境中可能不会实际增加)
  77. // 但至少验证界面没有错误
  78. const hasError = await agoraSTTPage.hasError();
  79. expect(hasError).toBe(false);
  80. });
  81. test('清空转录结果功能', async ({ agoraSTTPage }) => {
  82. // 加入频道
  83. await agoraSTTPage.joinChannel();
  84. // 验证清空按钮可见
  85. await expect(agoraSTTPage.clearTranscriptionsButton).toBeVisible();
  86. // 点击清空按钮
  87. await agoraSTTPage.clearTranscriptions();
  88. // 验证转录结果被清空
  89. const hasFinalTranscriptions = await agoraSTTPage.hasFinalTranscriptions();
  90. expect(hasFinalTranscriptions).toBe(false);
  91. });
  92. test('错误处理机制', async ({ agoraSTTPage, page }) => {
  93. // 模拟网络错误场景
  94. // 在加入频道前断开网络连接
  95. await page.context().setOffline(true);
  96. // 尝试加入频道(应该失败)
  97. await agoraSTTPage.joinChannelButton.click();
  98. // 验证错误提示显示
  99. await expect(agoraSTTPage.errorAlert).toBeVisible({ timeout: 5000 });
  100. // 恢复网络连接
  101. await page.context().setOffline(false);
  102. // 再次尝试加入频道(应该成功)
  103. await agoraSTTPage.joinChannelButton.click();
  104. await expect(agoraSTTPage.connectionStatusBadge).toHaveText('已连接', { timeout: 10000 });
  105. });
  106. test('响应式布局 - 桌面端', async ({ agoraSTTPage, page }) => {
  107. await page.setViewportSize({ width: 1200, height: 800 });
  108. await agoraSTTPage.expectToBeVisible();
  109. // 验证桌面端布局元素
  110. await expect(agoraSTTPage.pageTitle).toBeVisible();
  111. await expect(agoraSTTPage.joinChannelButton).toBeVisible();
  112. await expect(agoraSTTPage.usageInstructions).toBeVisible();
  113. });
  114. test('响应式布局 - 平板端', async ({ agoraSTTPage, page }) => {
  115. await page.setViewportSize({ width: 768, height: 1024 });
  116. await agoraSTTPage.expectToBeVisible();
  117. // 验证平板端布局
  118. await expect(agoraSTTPage.pageTitle).toBeVisible();
  119. await expect(agoraSTTPage.joinChannelButton).toBeVisible();
  120. });
  121. test('响应式布局 - 移动端', async ({ agoraSTTPage, page }) => {
  122. await page.setViewportSize({ width: 375, height: 667 });
  123. await agoraSTTPage.expectToBeVisible();
  124. // 验证移动端布局
  125. await expect(agoraSTTPage.pageTitle).toBeVisible();
  126. await expect(agoraSTTPage.joinChannelButton).toBeVisible();
  127. });
  128. test('无障碍功能验证', async ({ agoraSTTPage, page }) => {
  129. // 验证ARIA标签
  130. await expect(agoraSTTPage.joinChannelButton).toHaveAttribute('aria-label', /加入频道|连接中\.\.\./);
  131. // 验证键盘导航
  132. await page.keyboard.press('Tab');
  133. await expect(agoraSTTPage.joinChannelButton).toBeFocused();
  134. // 验证语义化标记
  135. await expect(agoraSTTPage.page.getByRole('region', { name: '语音转文字组件' })).toBeVisible();
  136. });
  137. test('Token和配置统一获取验证', async ({ agoraSTTPage, page }) => {
  138. // 监听网络请求,验证Token API调用
  139. const tokenApiRequests: string[] = [];
  140. page.on('request', (request) => {
  141. if (request.url().includes('/api/v1/agora/token')) {
  142. tokenApiRequests.push(request.url());
  143. }
  144. });
  145. // 加入频道,这会触发Token和配置获取
  146. await agoraSTTPage.joinChannel();
  147. // 验证Token API被调用
  148. expect(tokenApiRequests.length).toBeGreaterThan(0);
  149. // 验证请求参数包含正确的type和channel
  150. const requestUrl = tokenApiRequests[0];
  151. expect(requestUrl).toContain('type=rtc');
  152. expect(requestUrl).toContain('channel=');
  153. // 验证连接状态正确更新
  154. const connectionStatus = await agoraSTTPage.getConnectionStatus();
  155. expect(connectionStatus).toBe('已连接');
  156. // 验证组件功能正常
  157. await expect(agoraSTTPage.startRecordingButton).toBeVisible();
  158. await expect(agoraSTTPage.clearTranscriptionsButton).toBeVisible();
  159. });
  160. test('配置常量显示验证', async ({ agoraSTTPage, page }) => {
  161. // 加入频道以获取配置常量
  162. await agoraSTTPage.joinChannel();
  163. // 验证配置信息显示(如果组件显示配置信息)
  164. // 这里可以检查页面是否显示了从API获取的配置常量
  165. // 验证组件状态正常,没有错误
  166. const hasError = await agoraSTTPage.hasError();
  167. expect(hasError).toBe(false);
  168. // 验证连接状态
  169. const connectionStatus = await agoraSTTPage.getConnectionStatus();
  170. expect(connectionStatus).toBe('已连接');
  171. });
  172. test('Token API错误处理', async ({ agoraSTTPage, page }) => {
  173. // 模拟Token API失败
  174. await page.route('**/api/v1/agora/token*', async (route) => {
  175. await route.fulfill({
  176. status: 500,
  177. contentType: 'application/json',
  178. body: JSON.stringify({ message: 'Token生成失败' })
  179. });
  180. });
  181. // 尝试加入频道
  182. await agoraSTTPage.joinChannelButton.click();
  183. // 验证错误处理
  184. await expect(agoraSTTPage.errorAlert).toBeVisible({ timeout: 5000 });
  185. // 验证连接状态未改变
  186. const connectionStatus = await agoraSTTPage.getConnectionStatus();
  187. expect(connectionStatus).toBe('未连接');
  188. // 恢复正常路由
  189. await page.unroute('**/api/v1/agora/token*');
  190. });
  191. test('完整流程测试', async ({ agoraSTTPage }) => {
  192. // 完整测试语音转文字流程
  193. // 1. 初始状态验证
  194. await expect(agoraSTTPage.joinChannelButton).toBeVisible();
  195. // 2. 加入频道
  196. await agoraSTTPage.joinChannel();
  197. // 3. 开始录音
  198. await agoraSTTPage.startRecording();
  199. // 4. 等待录音过程
  200. await agoraSTTPage.page.waitForTimeout(3000);
  201. // 5. 停止录音
  202. await agoraSTTPage.stopRecording();
  203. // 6. 离开频道
  204. await agoraSTTPage.leaveChannel();
  205. // 7. 验证回到初始状态
  206. await expect(agoraSTTPage.joinChannelButton).toBeVisible();
  207. await expect(agoraSTTPage.leaveChannelButton).not.toBeVisible();
  208. });
  209. test.skip('麦克风权限被拒绝场景', async ({ agoraSTTPage, page }) => {
  210. // 跳过此测试,因为在Playwright测试中无法模拟具体的麦克风权限拒绝
  211. // 在实际环境中,当麦克风权限被拒绝时,组件应该显示相应的错误信息
  212. // 加入频道
  213. await agoraSTTPage.joinChannel();
  214. // 验证组件能够处理权限拒绝的情况
  215. const hasError = await agoraSTTPage.hasError();
  216. // 组件应该优雅地处理权限问题,而不是崩溃
  217. expect(hasError).toBe(false);
  218. });
  219. });