import { Page, Locator, expect } from '@playwright/test'; export class AgoraSTTPage { readonly page: Page; readonly pageTitle: Locator; readonly joinChannelButton: Locator; readonly leaveChannelButton: Locator; readonly startRecordingButton: Locator; readonly stopRecordingButton: Locator; readonly clearTranscriptionsButton: Locator; readonly connectionStatusBadge: Locator; readonly recordingStatusBadge: Locator; readonly microphonePermissionBadge: Locator; readonly transcriptionCountBadge: Locator; readonly errorAlert: Locator; readonly interimTranscription: Locator; readonly finalTranscriptions: Locator; readonly usageInstructions: Locator; constructor(page: Page) { this.page = page; this.pageTitle = page.getByRole('heading', { name: '语音转文字' }); this.joinChannelButton = page.getByTestId('join-channel-button'); this.leaveChannelButton = page.getByTestId('leave-channel-button'); this.startRecordingButton = page.getByTestId('start-recording-button'); this.stopRecordingButton = page.getByTestId('stop-recording-button'); this.clearTranscriptionsButton = page.getByTestId('clear-transcriptions-button'); // 状态徽章 this.connectionStatusBadge = page.getByText(/已连接|未连接/).first(); this.recordingStatusBadge = page.getByText(/录制中|未录制/).first(); this.microphonePermissionBadge = page.getByText(/麦克风已授权|麦克风被拒绝|麦克风权限/).first(); this.transcriptionCountBadge = page.getByText(/条转录/).first(); // 转录结果显示 this.errorAlert = page.getByRole('alert'); this.interimTranscription = page.getByText('正在识别...').first(); this.finalTranscriptions = page.getByText('转录结果:').first(); this.usageInstructions = page.getByText('使用说明:'); } async expectToBeVisible(options?: { timeout?: number }) { await expect(this.pageTitle).toBeVisible(options); await expect(this.joinChannelButton).toBeVisible(options); } async navigateFromDashboard(dashboardPage: any) { // 检查是否为移动端,需要先打开菜单 const isMobile = (this.page.viewportSize()?.width || 0) < 768; if (isMobile) { // 移动端需要先点击菜单按钮 const menuButton = this.page.getByTestId('mobile-menu-button'); await expect(menuButton).toBeVisible({ timeout: 10000 }); await menuButton.click({ timeout: 15000 }); await this.page.waitForTimeout(1000); // 等待菜单完全展开 } // 导航到Agora STT页面 const agoraSTTLink = this.page.getByRole('button', { name: '语音转文字' }).first(); await expect(agoraSTTLink).toBeVisible({ timeout: 10000 }); await agoraSTTLink.click({ timeout: 10000 }); await this.page.waitForLoadState('networkidle'); await this.expectToBeVisible(); } async goto() { // 直接访问Agora STT页面URL await this.page.goto('/admin/agora-stt'); await this.page.waitForLoadState('networkidle'); await this.expectToBeVisible(); } async joinChannel() { await this.joinChannelButton.click(); // 等待连接状态更新 await expect(this.connectionStatusBadge).toHaveText('已连接', { timeout: 15000 }); // 等待按钮状态更新 - 先等待加入按钮消失 await expect(this.joinChannelButton).not.toBeVisible({ timeout: 5000 }); // 然后等待离开频道按钮可见 await expect(this.leaveChannelButton).toBeVisible({ timeout: 10000 }); } async leaveChannel() { await this.leaveChannelButton.click(); await expect(this.connectionStatusBadge).toHaveText('未连接'); } async startRecording() { await this.startRecordingButton.click(); // 等待录制状态更新,增加超时时间 await expect(this.recordingStatusBadge).toHaveText('录制中', { timeout: 15000 }); } async stopRecording() { await this.stopRecordingButton.click(); await expect(this.recordingStatusBadge).toHaveText('未录制'); } async clearTranscriptions() { await this.clearTranscriptionsButton.click(); // 验证转录结果被清空 await expect(this.finalTranscriptions).not.toBeVisible(); } async getConnectionStatus(): Promise { return await this.connectionStatusBadge.textContent() || ''; } async getRecordingStatus(): Promise { return await this.recordingStatusBadge.textContent() || ''; } async getMicrophonePermissionStatus(): Promise { return await this.microphonePermissionBadge.textContent() || ''; } async getTranscriptionCount(): Promise { const text = await this.transcriptionCountBadge.textContent() || ''; const match = text.match(/(\d+)\s*条转录/); return match ? parseInt(match[1]) : 0; } async hasError(): Promise { return await this.errorAlert.isVisible(); } async hasInterimTranscription(): Promise { return await this.interimTranscription.isVisible(); } async hasFinalTranscriptions(): Promise { return await this.finalTranscriptions.isVisible(); } clone(newPage: Page): AgoraSTTPage { return new AgoraSTTPage(newPage); } }