feat: Add TURN server support
All checks were successful
Queue Release Build / prepare (push) Successful in 15s
Deploy Web Apps / deploy (push) Successful in 5m35s
Queue Release Build / build-linux (push) Successful in 24m45s
Queue Release Build / build-windows (push) Successful in 13m52s
Queue Release Build / finalize (push) Successful in 23s

This commit is contained in:
2026-04-18 21:27:04 +02:00
parent 167c45ba8d
commit 44588e8789
60 changed files with 2404 additions and 365 deletions

View File

@@ -0,0 +1,126 @@
import { test, expect } from '../../fixtures/multi-client';
import { RegisterPage } from '../../pages/register.page';
test.describe('ICE server settings', () => {
test.describe.configure({ timeout: 120_000 });
async function registerAndOpenNetworkSettings(page: import('@playwright/test').Page, suffix: string) {
const register = new RegisterPage(page);
await register.goto();
await register.register(`user_${suffix}`, 'IceTestUser', 'TestPass123!');
await expect(page.getByPlaceholder('Search servers...')).toBeVisible({ timeout: 30_000 });
await page.getByTitle('Settings').click();
await expect(page.getByRole('dialog')).toBeVisible({ timeout: 10_000 });
await page.getByRole('button', { name: 'Network' }).click();
}
test('allows adding, removing, and reordering ICE servers', async ({ createClient }) => {
const client = await createClient();
const { page } = client;
const suffix = `ice_${Date.now()}`;
await test.step('Register and open Network settings', async () => {
await registerAndOpenNetworkSettings(page, suffix);
});
const iceSection = page.getByTestId('ice-server-settings');
await test.step('Default STUN servers are listed', async () => {
await expect(iceSection).toBeVisible({ timeout: 5_000 });
const entries = page.getByTestId('ice-server-list').locator('[data-testid^="ice-entry-"]');
await expect(entries.first()).toBeVisible({ timeout: 5_000 });
const count = await entries.count();
expect(count).toBeGreaterThanOrEqual(1);
});
await test.step('Add a STUN server', async () => {
await page.getByTestId('ice-type-select').selectOption('stun');
await page.getByTestId('ice-url-input').fill('stun:custom.example.com:3478');
await page.getByTestId('ice-add-button').click();
await expect(page.getByText('stun:custom.example.com:3478')).toBeVisible({ timeout: 5_000 });
});
await test.step('Add a TURN server with credentials', async () => {
await page.getByTestId('ice-type-select').selectOption('turn');
await page.getByTestId('ice-url-input').fill('turn:relay.example.com:443');
await page.getByTestId('ice-username-input').fill('testuser');
await page.getByTestId('ice-credential-input').fill('testpass');
await page.getByTestId('ice-add-button').click();
await expect(page.getByText('turn:relay.example.com:443')).toBeVisible({ timeout: 5_000 });
await expect(page.getByText('User: testuser')).toBeVisible({ timeout: 5_000 });
});
await test.step('Remove first entry and verify count decreases', async () => {
const entries = page.getByTestId('ice-server-list').locator('[data-testid^="ice-entry-"]');
const countBefore = await entries.count();
await entries.first().getByTitle('Remove')
.click();
await expect(entries).toHaveCount(countBefore - 1, { timeout: 5_000 });
});
await test.step('Reorder: move second entry up', async () => {
const entries = page.getByTestId('ice-server-list').locator('[data-testid^="ice-entry-"]');
const count = await entries.count();
if (count >= 2) {
const secondText = await entries.nth(1).locator('p')
.first()
.textContent();
if (!secondText) {
throw new Error('Expected ICE server entry text before reordering');
}
await entries.nth(1).getByTitle('Move up (higher priority)')
.click();
// Wait for the moved entry text to appear at position 0
await expect(entries.first().locator('p')
.first()).toHaveText(secondText, { timeout: 5_000 });
}
});
await test.step('Restore defaults resets list', async () => {
await page.getByTestId('ice-restore-defaults').click();
await expect(page.getByText('turn:relay.example.com:443')).not.toBeVisible({ timeout: 3_000 });
const entries = page.getByTestId('ice-server-list').locator('[data-testid^="ice-entry-"]');
await expect(entries.first()).toBeVisible({ timeout: 5_000 });
});
await test.step('Settings persist after page reload', async () => {
await page.getByTestId('ice-type-select').selectOption('stun');
await page.getByTestId('ice-url-input').fill('stun:persist-test.example.com:3478');
await page.getByTestId('ice-add-button').click();
await expect(page.getByText('stun:persist-test.example.com:3478')).toBeVisible({ timeout: 5_000 });
await page.reload({ waitUntil: 'domcontentloaded' });
await page.getByTitle('Settings').click();
await expect(page.getByRole('dialog')).toBeVisible({ timeout: 10_000 });
await page.getByRole('button', { name: 'Network' }).click();
await expect(page.getByText('stun:persist-test.example.com:3478')).toBeVisible({ timeout: 10_000 });
});
});
test('validates TURN entries require credentials', async ({ createClient }) => {
const client = await createClient();
const { page } = client;
const suffix = `iceval_${Date.now()}`;
await test.step('Register and open Network settings', async () => {
await registerAndOpenNetworkSettings(page, suffix);
});
await test.step('Adding TURN without credentials shows error', async () => {
await page.getByTestId('ice-type-select').selectOption('turn');
await page.getByTestId('ice-url-input').fill('turn:noncred.example.com:443');
await page.getByTestId('ice-add-button').click();
await expect(page.getByText('Username is required for TURN servers')).toBeVisible({ timeout: 5_000 });
});
});
});