agora-stt.spec.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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. await expect(agoraSTTPage.startRecordingButton).toBeVisible();
  56. // 验证录制状态初始为未录制
  57. const initialRecordingStatus = await agoraSTTPage.getRecordingStatus();
  58. expect(initialRecordingStatus).toBe('未录制');
  59. // 验证麦克风权限状态
  60. const microphoneStatus = await agoraSTTPage.getMicrophonePermissionStatus();
  61. expect(microphoneStatus).toBe('麦克风权限');
  62. });
  63. test('转录结果显示功能', async ({ agoraSTTPage }) => {
  64. // 加入频道
  65. await agoraSTTPage.joinChannel();
  66. // 在测试环境中,我们无法实际进行录音
  67. // 因此只验证界面状态和按钮可见性
  68. // 验证开始录音按钮可见
  69. await expect(agoraSTTPage.startRecordingButton).toBeVisible();
  70. // 验证清空转录按钮可见
  71. await expect(agoraSTTPage.clearTranscriptionsButton).toBeVisible();
  72. // 验证界面没有错误
  73. const hasError = await agoraSTTPage.hasError();
  74. expect(hasError).toBe(false);
  75. });
  76. test('清空转录结果功能', async ({ agoraSTTPage }) => {
  77. // 加入频道
  78. await agoraSTTPage.joinChannel();
  79. // 验证清空按钮可见
  80. await expect(agoraSTTPage.clearTranscriptionsButton).toBeVisible();
  81. // 点击清空按钮
  82. await agoraSTTPage.clearTranscriptions();
  83. // 验证转录结果被清空
  84. const hasFinalTranscriptions = await agoraSTTPage.hasFinalTranscriptions();
  85. expect(hasFinalTranscriptions).toBe(false);
  86. });
  87. test('错误处理机制', async ({ agoraSTTPage, page }) => {
  88. // 模拟网络错误场景
  89. // 在加入频道前断开网络连接
  90. await page.context().setOffline(true);
  91. // 尝试加入频道(应该失败)
  92. await agoraSTTPage.joinChannelButton.click();
  93. // 验证错误提示显示
  94. await expect(agoraSTTPage.errorAlert).toBeVisible({ timeout: 10000 });
  95. // 恢复网络连接
  96. await page.context().setOffline(false);
  97. // 等待网络恢复和错误状态清除
  98. await page.waitForTimeout(2000);
  99. // 刷新页面重新开始
  100. await agoraSTTPage.goto();
  101. // 正常加入频道(应该成功)
  102. await agoraSTTPage.joinChannel();
  103. });
  104. test('响应式布局 - 桌面端', async ({ agoraSTTPage, page }) => {
  105. await page.setViewportSize({ width: 1200, height: 800 });
  106. await agoraSTTPage.expectToBeVisible();
  107. // 验证桌面端布局元素
  108. await expect(agoraSTTPage.pageTitle).toBeVisible();
  109. await expect(agoraSTTPage.joinChannelButton).toBeVisible();
  110. await expect(agoraSTTPage.usageInstructions).toBeVisible();
  111. });
  112. test('响应式布局 - 平板端', async ({ agoraSTTPage, page }) => {
  113. await page.setViewportSize({ width: 768, height: 1024 });
  114. await agoraSTTPage.expectToBeVisible();
  115. // 验证平板端布局
  116. await expect(agoraSTTPage.pageTitle).toBeVisible();
  117. await expect(agoraSTTPage.joinChannelButton).toBeVisible();
  118. });
  119. test('响应式布局 - 移动端', async ({ agoraSTTPage, page }) => {
  120. await page.setViewportSize({ width: 375, height: 667 });
  121. await agoraSTTPage.expectToBeVisible();
  122. // 验证移动端布局
  123. await expect(agoraSTTPage.pageTitle).toBeVisible();
  124. await expect(agoraSTTPage.joinChannelButton).toBeVisible();
  125. });
  126. test('无障碍功能验证', async ({ agoraSTTPage, page }) => {
  127. // 验证ARIA标签
  128. await expect(agoraSTTPage.joinChannelButton).toHaveAttribute('aria-label', /加入语音频道|连接中\.\.\./);
  129. // 验证语义化标记
  130. await expect(agoraSTTPage.page.getByRole('region', { name: '语音转文字组件' })).toBeVisible();
  131. // 验证按钮有正确的可访问性属性
  132. await expect(agoraSTTPage.joinChannelButton).toHaveAttribute('data-testid', 'join-channel-button');
  133. // 先加入频道,然后验证离开频道按钮的属性
  134. await agoraSTTPage.joinChannel();
  135. await expect(agoraSTTPage.leaveChannelButton).toHaveAttribute('data-testid', 'leave-channel-button');
  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=rtm');
  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 }) => {
  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. // 只验证按钮状态
  199. await expect(agoraSTTPage.startRecordingButton).toBeVisible();
  200. await expect(agoraSTTPage.clearTranscriptionsButton).toBeVisible();
  201. // 6. 离开频道
  202. await agoraSTTPage.leaveChannel();
  203. // 7. 验证回到初始状态
  204. await expect(agoraSTTPage.joinChannelButton).toBeVisible();
  205. await expect(agoraSTTPage.leaveChannelButton).not.toBeVisible();
  206. });
  207. test.skip('麦克风权限被拒绝场景', async ({ agoraSTTPage }) => {
  208. // 跳过此测试,因为在Playwright测试中无法模拟具体的麦克风权限拒绝
  209. // 在实际环境中,当麦克风权限被拒绝时,组件应该显示相应的错误信息
  210. // 加入频道
  211. await agoraSTTPage.joinChannel();
  212. // 验证组件能够处理权限拒绝的情况
  213. const hasError = await agoraSTTPage.hasError();
  214. // 组件应该优雅地处理权限问题,而不是崩溃
  215. expect(hasError).toBe(false);
  216. });
  217. });