Fix playwright tests for new radio status indicator

This commit is contained in:
Jack Kingsman
2026-03-08 14:30:47 -07:00
parent 5cb5c2ad25
commit 655066ed73
20 changed files with 46 additions and 44 deletions
+5 -5
View File
@@ -33,7 +33,7 @@ test.describe('Apprise integration settings', () => {
test('create apprise via UI, configure URLs, save as enabled', async ({ page }) => {
await openFanoutSettings(page);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Open add menu and pick Apprise
await page.getByRole('button', { name: 'Add Integration' }).click();
@@ -89,7 +89,7 @@ test.describe('Apprise integration settings', () => {
createdAppriseId = apprise.id;
await openFanoutSettings(page);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Click Edit on our apprise config
const row = fanoutHeader(page, 'API Apprise');
@@ -129,7 +129,7 @@ test.describe('Apprise integration settings', () => {
createdAppriseId = apprise.id;
await openFanoutSettings(page);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
const row = fanoutHeader(page, 'Scope Apprise');
await expect(row).toBeVisible();
@@ -163,7 +163,7 @@ test.describe('Apprise integration settings', () => {
createdAppriseId = apprise.id;
await openFanoutSettings(page);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Should show "Disabled" status text
const row = fanoutHeader(page, 'Disabled Apprise');
@@ -192,7 +192,7 @@ test.describe('Apprise integration settings', () => {
createdAppriseId = apprise.id;
await openFanoutSettings(page);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
const row = fanoutHeader(page, 'Delete Me Apprise');
await expect(row).toBeVisible();
+1 -1
View File
@@ -42,7 +42,7 @@ test.describe('Bot functionality', () => {
// --- Step 2: Verify bot appears in settings UI ---
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await page.getByText('Settings').click();
await page.getByRole('button', { name: /MQTT.*Automation/ }).click();
@@ -35,7 +35,7 @@ test.describe('Channel info pane', () => {
test('opens channel info pane and shows message activity', async ({ page }) => {
await page.goto(`/#channel/${channelKey}/flightless`);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Wait for messages to load
await expect(page.getByText('seed-0')).toBeVisible({ timeout: 15_000 });
@@ -83,7 +83,7 @@ test.describe('Message search and jump-to-message', () => {
test('search finds seeded messages', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Open search view via sidebar
await page.getByText('Message Search').click();
@@ -109,7 +109,7 @@ test.describe('Message search and jump-to-message', () => {
test('clicking a search result jumps to the message in conversation', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Open search
await page.getByText('Message Search').click();
@@ -135,7 +135,7 @@ test.describe('Message search and jump-to-message', () => {
test('search returns no results for nonsense query', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await page.getByText('Message Search').click();
@@ -33,7 +33,7 @@ test.describe('Channel message persistence across delete/re-add', () => {
// Verify message appears in UI
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await page.getByText(channelName, { exact: true }).first().click();
await expect(page.getByText(testMessage)).toBeVisible({ timeout: 15_000 });
@@ -42,7 +42,7 @@ test.describe('Channel message persistence across delete/re-add', () => {
// Verify channel is gone from sidebar
await page.reload();
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await expect(page.getByText(channelName, { exact: true })).not.toBeVisible({ timeout: 10_000 });
// Re-create the same hashtag channel (derives same key)
@@ -51,7 +51,7 @@ test.describe('Channel message persistence across delete/re-add', () => {
// Navigate to it
await page.reload();
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await page.getByText(channelName, { exact: true }).first().click();
// Verify original message is still visible as outgoing
+3 -3
View File
@@ -25,7 +25,7 @@ test.describe('Contacts sidebar & info pane', () => {
}
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Click the contact in the sidebar
await page.getByText(named.name!, { exact: true }).first().click();
@@ -46,7 +46,7 @@ test.describe('Contacts sidebar & info pane', () => {
}
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Open contact conversation
await page.getByText(named.name!, { exact: true }).first().click();
@@ -74,7 +74,7 @@ test.describe('Contacts sidebar & info pane', () => {
}
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await page.getByText(named.name!, { exact: true }).first().click();
const escapedName = escapeRegex(named.name!.trim());
+2 -2
View File
@@ -14,7 +14,7 @@ test.describe('Conversation deletion flow', () => {
const channel = await createChannel(channelName);
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await page.getByText(channelName, { exact: true }).first().click();
await expect(page.getByPlaceholder(new RegExp(`message\\s+${channelName}`, 'i'))).toBeVisible();
@@ -40,7 +40,7 @@ test.describe('Conversation deletion flow', () => {
const channel = await createChannel(channelName);
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await page.getByText(channelName, { exact: true }).first().click();
await expect(page.getByPlaceholder(new RegExp(`message\\s+${channelName}`, 'i'))).toBeVisible();
+1 -1
View File
@@ -16,7 +16,7 @@ test.describe('Create contact flow', () => {
test('create a new contact via the new message modal', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Open new message modal
await page.getByTitle('New Message').click();
+2 -2
View File
@@ -23,7 +23,7 @@ test.describe('Create hashtag channel flow', () => {
test('create a hashtag channel via UI', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Open new message modal
await page.getByTitle('New Message').click();
@@ -47,7 +47,7 @@ test.describe('Create hashtag channel flow', () => {
test('create & add another keeps modal open', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await page.getByTitle('New Message').click();
const dialog = page.getByRole('dialog');
+2 -2
View File
@@ -39,7 +39,7 @@ test.describe('Favorites persistence', () => {
test('add and remove favorite channel with persistence across reload', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await page.getByText(channelName, { exact: true }).first().click();
@@ -57,7 +57,7 @@ test.describe('Favorites persistence', () => {
.toBe(true);
await page.reload();
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await page.getByText(channelName, { exact: true }).first().click();
await expect(page.getByTitle('Remove from favorites')).toBeVisible();
await expect(page.getByText('Favorites')).toBeVisible();
+3 -3
View File
@@ -61,7 +61,7 @@ test.describe('Hash routing and conversation identity', () => {
const legacyToken = channelName.slice(1); // no leading '#'
await page.goto(`/#channel/${encodeURIComponent(legacyToken)}`);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await expect(
page.getByPlaceholder(new RegExp(`message\\s+${escapeRegex(channelName)}`, 'i'))
).toBeVisible();
@@ -72,7 +72,7 @@ test.describe('Hash routing and conversation identity', () => {
test('full-key contact hash selects the exact contact even with shared prefixes', async ({ page }) => {
await page.goto(`/#contact/${contactBKey}`);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await expect(
page.getByPlaceholder(new RegExp(`message\\s+${escapeRegex(contactBName)}`, 'i'))
).toBeVisible();
@@ -84,7 +84,7 @@ test.describe('Hash routing and conversation identity', () => {
test('legacy contact-name hash resolves and rewrites to stable full-key hash', async ({ page }) => {
await page.goto(`/#contact/${encodeURIComponent(contactAName)}`);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await expect(
page.getByPlaceholder(new RegExp(`message\\s+${escapeRegex(contactAName)}`, 'i'))
).toBeVisible();
+2 -2
View File
@@ -4,8 +4,8 @@ test.describe('Health & UI basics', () => {
test('page loads and shows connected status', async ({ page }) => {
await page.goto('/');
// Status bar shows "Connected"
await expect(page.getByText('Connected')).toBeVisible();
// Status bar shows the connected-ready label
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Sidebar is visible with key sections
await expect(page.getByRole('heading', { name: 'Conversations' })).toBeVisible();
@@ -34,7 +34,7 @@ test.describe('Historical packet decryption', () => {
// Open the UI
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Open new message modal → Hashtag tab
await page.getByTitle('New Message').click();
+2 -2
View File
@@ -59,7 +59,7 @@ test.describe('Incoming mesh messages', () => {
await nudgeEchoBot();
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Record existing message counts per channel so we can detect new ones
const channels = await getChannels();
@@ -110,7 +110,7 @@ test.describe('Incoming mesh messages', () => {
await nudgeEchoBot();
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Record baselines
const channels = await getChannels();
@@ -28,7 +28,7 @@ test.describe('Reopen last conversation (device-local)', () => {
test('reopens last viewed conversation on startup when enabled', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await expect.poll(() => new URL(page.url()).hash).toBe('');
await page.getByText(channelName, { exact: true }).first().click();
@@ -51,7 +51,7 @@ test.describe('Reopen last conversation (device-local)', () => {
test('clears local storage and falls back to default when disabled', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await page.getByText(channelName, { exact: true }).first().click();
await expect(
+1 -1
View File
@@ -27,7 +27,7 @@ test.describe('Sidebar search/filter', () => {
test('search filters conversations by name', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Both channels should be visible
await expect(page.getByText(nameA, { exact: true })).toBeVisible();
+1 -1
View File
@@ -3,7 +3,7 @@ import { test, expect } from '@playwright/test';
test.describe('Sidebar sort toggle', () => {
test('toggle sort order between A-Z and recent', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// There are multiple sort toggles (Channels, Contacts, Repeaters sections).
// Use .first() to target the Channels sort toggle.
+1 -1
View File
@@ -3,7 +3,7 @@ import { test, expect } from '@playwright/test';
test.describe('Statistics page', () => {
test('statistics section shows data', async ({ page }) => {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Open settings
await page.getByText('Settings').click();
+1 -1
View File
@@ -9,7 +9,7 @@ test.describe('Unread badge/pip', () => {
seedChannelUnread({ channelName: CHANNEL_NAME, unreadCount: 3 });
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Find the channel in the sidebar
const channelRow = page.getByText(CHANNEL_NAME, { exact: true }).first();
+5 -5
View File
@@ -33,7 +33,7 @@ test.describe('Webhook integration settings', () => {
test('create webhook via UI, configure, save as enabled, verify in list', async ({ page }) => {
await openFanoutSettings(page);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Open add menu and pick Webhook
await page.getByRole('button', { name: 'Add Integration' }).click();
@@ -75,7 +75,7 @@ test.describe('Webhook integration settings', () => {
const existingIds = new Set(existingConfigs.map((cfg) => cfg.id));
await openFanoutSettings(page);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
await page.getByRole('button', { name: 'Add Integration' }).click();
await page.getByRole('menuitem', { name: 'Webhook' }).click();
@@ -105,7 +105,7 @@ test.describe('Webhook integration settings', () => {
createdWebhookId = webhook.id;
await openFanoutSettings(page);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Click Edit on our webhook
const row = fanoutHeader(page, 'API Webhook');
@@ -139,7 +139,7 @@ test.describe('Webhook integration settings', () => {
createdWebhookId = webhook.id;
await openFanoutSettings(page);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Click Edit
const row = fanoutHeader(page, 'Scope Webhook');
@@ -173,7 +173,7 @@ test.describe('Webhook integration settings', () => {
createdWebhookId = webhook.id;
await openFanoutSettings(page);
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Click Edit
const row = fanoutHeader(page, 'Delete Me Webhook');
+4 -2
View File
@@ -15,7 +15,7 @@ test.describe('Radio settings', () => {
try {
await page.goto('/');
await expect(page.getByText('Connected')).toBeVisible();
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// --- Step 1: Change the name via settings UI ---
await page.getByText('Settings').click();
@@ -36,7 +36,9 @@ test.describe('Radio settings', () => {
// --- Step 3: Verify persistence across page reload ---
await page.reload();
await expect(page.getByText('Connected')).toBeVisible({ timeout: 15_000 });
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible({
timeout: 15_000,
});
await page.getByText('Settings').click();
await expect(page.locator('#name')).toHaveValue(testName, { timeout: 10_000 });