import { type Page, type Locator, expect } from '@playwright/test'; export class ServerSearchPage { readonly searchInput: Locator; readonly createServerButton: Locator; readonly railDashboardButton: Locator; readonly settingsButton: Locator; // Create server page readonly serverNameInput: Locator; readonly serverDescriptionInput: Locator; readonly serverTopicInput: Locator; readonly signalEndpointSelect: Locator; readonly advancedSettingsToggle: Locator; readonly privateCheckbox: Locator; readonly serverPasswordInput: Locator; readonly createSubmitButton: Locator; readonly cancelButton: Locator; constructor(private page: Page) { // Server discovery lives on /servers via . this.searchInput = page.getByPlaceholder('Search servers...'); this.railDashboardButton = page.locator('button[title="Dashboard"]'); // Dashboard "Create Server" entry point. this.createServerButton = page.getByRole('link', { name: 'Create Server' }).first(); this.settingsButton = page.locator('button[title="Settings"]'); // Create-server page elements. this.serverNameInput = page.locator('#create-server-name'); this.serverDescriptionInput = page.locator('#create-server-description'); this.serverTopicInput = page.locator('#create-server-topic'); this.signalEndpointSelect = page.locator('#create-server-signal-endpoint'); this.advancedSettingsToggle = page.getByRole('button', { name: 'Advanced settings' }); this.privateCheckbox = page.locator('#create-server-private'); this.serverPasswordInput = page.locator('#create-server-password'); this.createSubmitButton = page.locator('#create-server-submit'); this.cancelButton = page.locator('#create-server-cancel'); } async goto() { await this.page.goto('/servers'); } async createServer(name: string, options?: { description?: string; topic?: string; sourceId?: string }) { await this.page.goto('/create-server', { waitUntil: 'domcontentloaded' }); await expect(this.serverNameInput).toBeVisible({ timeout: 10_000 }); await this.serverNameInput.fill(name); if (options?.description) { await this.serverDescriptionInput.fill(options.description); } if (options?.topic || options?.sourceId) { if (!await this.serverTopicInput.isVisible()) { await this.advancedSettingsToggle.click(); } await expect(this.serverTopicInput).toBeVisible({ timeout: 10_000 }); if (options?.topic) { await this.serverTopicInput.fill(options.topic); } if (options?.sourceId) { await this.signalEndpointSelect.selectOption(options.sourceId); } } await this.createSubmitButton.click(); } async joinSavedRoom(name: string) { await this.page.getByRole('button', { name }).click(); } async joinServerFromSearch(name: string, options: { acceptPluginDownloads?: boolean } = {}) { await this.page.goto('/servers', { waitUntil: 'domcontentloaded' }); await expect(this.searchInput).toBeVisible({ timeout: 15_000 }); await this.searchInput.fill(name); const serverCard = this.page.locator('div[title]', { hasText: name }).first(); await expect(serverCard).toBeVisible({ timeout: 15_000 }); await serverCard.dblclick(); if (options.acceptPluginDownloads) { const pluginConsentDialog = this.page.getByRole('dialog', { name: /uses plugins/ }); await expect(pluginConsentDialog).toBeVisible({ timeout: 20_000 }); await pluginConsentDialog.getByRole('button', { name: 'Accept and join' }).click(); } } }