- Fix dialog scrollability (flex layout + max-h-[90dvh]) and increase L4 dialog to lg width - Add styled enable card to L4 dialog matching proxy host pattern - Unify section colors across proxy host and L4 dialogs (cyan=LB, emerald=DNS, violet=upstream DNS, rose=geo, amber=mTLS) - Improve light mode contrast: muted-foreground oklch 0.552→0.502, remove opacity modifiers on secondary text - Improve dark mode: boost muted-foreground to 0.85, increase border opacity 10%→16%, input 15%→20% - Add bg-card to DataTable wrapper and bg-muted/40 to table headers for surface hierarchy - Add semantic badge variants (success, warning, info, muted) and StatusChip dark mode fix - Add server-side sortable columns to Proxy Hosts and L4 Proxy Hosts (name, upstream, status, protocol, listen) - Add sortKey to DataTable Column type with clickable sort headers (ArrowUp/Down indicators, URL param driven) - Fix E2E test selectors for shadcn UI (label associations, combobox roles, dropdown menus, mobile drawer) - Add htmlFor/id to proxy host form fields and aria-labels to select triggers for accessibility - Add sorting E2E tests for both proxy host pages Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
81 lines
2.8 KiB
TypeScript
81 lines
2.8 KiB
TypeScript
/**
|
|
* Higher-level helpers for creating L4 proxy hosts in E2E tests.
|
|
*
|
|
* All helpers accept a Playwright `Page` (pre-authenticated via the
|
|
* global storageState) so they integrate cleanly with the standard
|
|
* `page` test fixture.
|
|
*/
|
|
import { expect, type Page } from '@playwright/test';
|
|
|
|
export interface L4ProxyHostConfig {
|
|
name: string;
|
|
protocol?: 'tcp' | 'udp';
|
|
listenAddress: string;
|
|
upstream: string; // e.g. "tcp-echo:9000"
|
|
matcherType?: 'none' | 'tls_sni' | 'http_host' | 'proxy_protocol';
|
|
matcherValue?: string; // comma-separated
|
|
tlsTermination?: boolean;
|
|
proxyProtocolReceive?: boolean;
|
|
proxyProtocolVersion?: 'v1' | 'v2';
|
|
}
|
|
|
|
/**
|
|
* Create an L4 proxy host via the browser UI.
|
|
*/
|
|
export async function createL4ProxyHost(page: Page, config: L4ProxyHostConfig): Promise<void> {
|
|
await page.goto('/l4-proxy-hosts');
|
|
await page.getByRole('button', { name: /create l4 host/i }).click();
|
|
await expect(page.getByRole('dialog')).toBeVisible();
|
|
|
|
await page.getByLabel('Name').fill(config.name);
|
|
|
|
// Protocol select (shadcn Select renders a button with role="combobox")
|
|
if (config.protocol && config.protocol !== 'tcp') {
|
|
await page.getByRole('combobox', { name: 'Protocol' }).first().click();
|
|
await page.getByRole('option', { name: new RegExp(config.protocol, 'i') }).click();
|
|
}
|
|
|
|
await page.getByLabel('Listen Address').fill(config.listenAddress);
|
|
await page.getByLabel('Upstreams').fill(config.upstream);
|
|
|
|
// Matcher type
|
|
if (config.matcherType && config.matcherType !== 'none') {
|
|
await page.getByLabel('Matcher').click();
|
|
const matcherLabels: Record<string, RegExp> = {
|
|
tls_sni: /tls sni/i,
|
|
http_host: /http host/i,
|
|
proxy_protocol: /proxy protocol/i,
|
|
};
|
|
await page.getByRole('option', { name: matcherLabels[config.matcherType] }).click();
|
|
|
|
if (config.matcherValue && (config.matcherType === 'tls_sni' || config.matcherType === 'http_host')) {
|
|
await page.getByLabel(/hostnames/i).fill(config.matcherValue);
|
|
}
|
|
}
|
|
|
|
// TLS termination
|
|
if (config.tlsTermination) {
|
|
await page.getByLabel(/tls termination/i).check();
|
|
}
|
|
|
|
// Proxy protocol receive
|
|
if (config.proxyProtocolReceive) {
|
|
await page.getByLabel(/accept inbound proxy/i).check();
|
|
}
|
|
|
|
// Proxy protocol version
|
|
if (config.proxyProtocolVersion) {
|
|
await page.getByLabel(/send proxy protocol/i).click();
|
|
await page.getByRole('option', { name: config.proxyProtocolVersion }).click();
|
|
}
|
|
|
|
// Submit
|
|
await page.getByRole('button', { name: /create/i }).click();
|
|
|
|
// Wait for success state (dialog closes or success alert)
|
|
await expect(page.getByRole('dialog')).not.toBeVisible({ timeout: 10_000 });
|
|
|
|
// Verify host appears in the table
|
|
await expect(page.getByRole('table').getByText(config.name)).toBeVisible({ timeout: 10_000 });
|
|
}
|