Files
sencho/e2e/nodes.spec.ts
T
SaelixCode 12bbe51a3a fix(e2e): fully rewrite nodes tests to handle Radix UI Select and remote type flow
- openAddNodeAsRemote helper: clicks #node-type (Radix combobox, not native select),
  picks the 'Remote' option, then waits for #node-api-url to appear — the API URL
  field is conditionally rendered only when type === 'remote'
- Fix getByLabel(/node name/i) → #node-name in both tests (missed in second test)
- Use .last() for submit button to avoid matching the Add Node trigger behind the dialog
- Remove typeSelect.selectOption() which throws 'not a select element' on Radix UI
2026-03-22 01:34:43 -04:00

59 lines
2.4 KiB
TypeScript

/**
* Node management E2E tests.
* Tests the SSRF validation we added (C2 fix) is surfaced in the UI.
*/
import { test, expect } from '@playwright/test';
import { loginAs } from './helpers';
test.describe('Node management', () => {
test.beforeEach(async ({ page }) => {
await loginAs(page);
// Open Settings modal then navigate to the Nodes section
await page.getByRole('button', { name: /settings/i }).click();
await page.getByRole('button', { name: /^nodes$/i }).click();
});
/**
* Open the Add Node dialog and switch the type to Remote so the API URL
* field becomes visible. Returns false (and skips) if the button isn't found.
*/
async function openAddNodeAsRemote(page: import('@playwright/test').Page): Promise<boolean> {
const addBtn = page.getByRole('button', { name: /add node/i }).first();
if (!await addBtn.isVisible()) {
test.skip();
return false;
}
await addBtn.click();
// Wait for the dialog form to be ready
await expect(page.locator('#node-name')).toBeVisible({ timeout: 5_000 });
// The API URL field only renders when type === 'remote'.
// #node-type is a Radix UI combobox — click to open, then pick the option.
await page.locator('#node-type').click();
await page.getByRole('option', { name: /remote/i }).click();
// Confirm the API URL field is now visible before proceeding
await expect(page.locator('#node-api-url')).toBeVisible({ timeout: 3_000 });
return true;
}
test('adding a node with localhost api_url shows a validation error', async ({ page }) => {
if (!await openAddNodeAsRemote(page)) return;
await page.locator('#node-name').fill('bad-node');
await page.locator('#node-api-url').fill('http://localhost:6379');
// Use .last() to target the dialog submit button, not the trigger
await page.getByRole('button', { name: /add node/i }).last().click();
await expect(page.getByText(/loopback|localhost/i)).toBeVisible({ timeout: 5_000 });
});
test('adding a node with an invalid URL shows an error', async ({ page }) => {
if (!await openAddNodeAsRemote(page)) return;
await page.locator('#node-name').fill('bad-url-node');
await page.locator('#node-api-url').fill('not-a-url-at-all');
await page.getByRole('button', { name: /add node/i }).last().click();
await expect(page.getByText(/valid url|invalid url/i)).toBeVisible({ timeout: 5_000 });
});
});