import { test, expect } from '@playwright/test'; test.describe('Proxy Hosts', () => { test.beforeEach(async ({ page }) => { await page.goto('/proxy-hosts'); }); test('page loads with Create Host button visible', async ({ page }) => { await expect(page.getByRole('button', { name: /create host/i })).toBeVisible(); }); test('clicking Create Host opens a dialog with form fields', async ({ page }) => { await page.getByRole('button', { name: /create host/i }).click(); await expect(page.getByRole('dialog')).toBeVisible(); await expect(page.getByLabel(/domains/i)).toBeVisible(); }); test('create a proxy host — appears in the table', async ({ page }) => { await page.getByRole('button', { name: /create host/i }).click(); await expect(page.getByRole('dialog')).toBeVisible(); await page.getByLabel('Name').fill('E2E Test Host'); await page.getByLabel(/domains/i).fill('e2etest.local'); // Upstream field uses placeholder text, not a label await page.getByPlaceholder('10.0.0.5:8080').fill('localhost:9999'); await page.getByRole('button', { name: /^create$/i }).click(); // Dialog should close and host appear in table await expect(page.getByRole('dialog')).not.toBeVisible({ timeout: 10000 }); await expect(page.getByRole('table').getByText('E2E Test Host')).toBeVisible({ timeout: 10000 }); }); test('clicking Name / Domain header sorts the table', async ({ page }) => { const sortBtn = page.getByRole('button', { name: 'Name / Domain' }); await expect(sortBtn).toBeVisible({ timeout: 10_000 }); // Click to sort ascending await sortBtn.click(); await expect(page).toHaveURL(/sortBy=name/); await expect(page).toHaveURL(/sortDir=asc/); // Click again to toggle to descending await sortBtn.click(); await expect(page).toHaveURL(/sortDir=desc/); }); test('clicking Status header sorts by enabled state', async ({ page }) => { const sortBtn = page.getByRole('button', { name: 'Status' }); await expect(sortBtn).toBeVisible(); await sortBtn.click(); await expect(page).toHaveURL(/sortBy=enabled/); }); test('delete proxy host removes it from table', async ({ page }) => { // Create one to delete await page.getByRole('button', { name: /create host/i }).click(); await expect(page.getByRole('dialog')).toBeVisible(); await page.getByLabel('Name').fill('Host To Delete'); await page.getByLabel(/domains/i).fill('delete-me.local'); await page.getByPlaceholder('10.0.0.5:8080').fill('localhost:7777'); await page.getByRole('button', { name: /^create$/i }).click(); await expect(page.getByRole('dialog')).not.toBeVisible({ timeout: 10000 }); await expect(page.getByRole('table').getByText('Host To Delete')).toBeVisible({ timeout: 10000 }); // Open the dropdown menu for that row and click Delete const row = page.locator('tr', { hasText: 'Host To Delete' }); await row.getByRole('button').first().click(); await page.getByRole('menuitem', { name: /delete/i }).click(); // Confirm dialog await expect(page.getByRole('dialog')).toBeVisible(); await page.getByRole('button', { name: /^delete$/i }).click(); // Wait for dialog to close, then verify the row is gone from the table await expect(page.getByRole('dialog')).not.toBeVisible({ timeout: 10000 }); await expect(page.locator('tbody').getByText('Host To Delete')).not.toBeVisible({ timeout: 5000 }); }); });