mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-03-28 17:43:05 +01:00
211 lines
7.1 KiB
TypeScript
211 lines
7.1 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import {
|
|
createFanoutConfig,
|
|
deleteFanoutConfig,
|
|
getFanoutConfigs,
|
|
} from '../helpers/api';
|
|
import { createCaptureServer, fanoutHeader, openFanoutSettings } from '../helpers/fanout';
|
|
|
|
test.describe('Apprise integration settings', () => {
|
|
let createdAppriseId: string | null = null;
|
|
let receiver: ReturnType<typeof createCaptureServer>;
|
|
let appriseUrl: string;
|
|
|
|
test.beforeAll(async () => {
|
|
receiver = createCaptureServer((port) => `json://127.0.0.1:${port}`);
|
|
appriseUrl = await receiver.listen();
|
|
});
|
|
|
|
test.afterAll(async () => {
|
|
receiver.close();
|
|
});
|
|
|
|
test.afterEach(async () => {
|
|
if (createdAppriseId) {
|
|
try {
|
|
await deleteFanoutConfig(createdAppriseId);
|
|
} catch {
|
|
console.warn('Failed to delete test apprise config');
|
|
}
|
|
createdAppriseId = null;
|
|
}
|
|
});
|
|
|
|
test('create apprise via UI, configure URLs, save as enabled', async ({ page }) => {
|
|
await openFanoutSettings(page);
|
|
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
|
|
|
|
// Open add menu and pick Apprise
|
|
await page.getByRole('button', { name: 'Add Integration' }).click();
|
|
await page.getByRole('menuitem', { name: 'Apprise' }).click();
|
|
|
|
// Should navigate to the detail/edit view with a numbered default name
|
|
await expect(page.locator('#fanout-edit-name')).toHaveValue(/Apprise #\d+/);
|
|
|
|
// Fill in notification URL
|
|
const urlsTextarea = page.locator('#fanout-apprise-urls');
|
|
await urlsTextarea.fill(appriseUrl);
|
|
|
|
// Verify preserve identity checkbox is checked by default
|
|
const preserveIdentity = page.getByText('Preserve identity on Discord');
|
|
await expect(preserveIdentity).toBeVisible();
|
|
|
|
// Verify include routing path checkbox is checked by default
|
|
const includePath = page.getByText('Include routing path in notifications');
|
|
await expect(includePath).toBeVisible();
|
|
|
|
// Rename it
|
|
const nameInput = page.locator('#fanout-edit-name');
|
|
await nameInput.clear();
|
|
await nameInput.fill('E2E Apprise');
|
|
|
|
// Save as enabled
|
|
await page.getByRole('button', { name: /Save as Enabled/i }).click();
|
|
await expect(page.getByText('Integration saved and enabled')).toBeVisible();
|
|
|
|
// Should be back on list view with our apprise config visible
|
|
await expect(page.getByText('E2E Apprise')).toBeVisible();
|
|
await expect(page.getByText(appriseUrl)).toBeVisible();
|
|
|
|
// Clean up via API
|
|
const configs = await getFanoutConfigs();
|
|
const apprise = configs.find((c) => c.name === 'E2E Apprise');
|
|
if (apprise) {
|
|
createdAppriseId = apprise.id;
|
|
}
|
|
});
|
|
|
|
test('create apprise via API, verify options persist after edit', async ({ page }) => {
|
|
const apprise = await createFanoutConfig({
|
|
type: 'apprise',
|
|
name: 'API Apprise',
|
|
config: {
|
|
urls: `${appriseUrl}\nslack://token_a/token_b/token_c`,
|
|
preserve_identity: false,
|
|
include_path: false,
|
|
},
|
|
enabled: true,
|
|
});
|
|
createdAppriseId = apprise.id;
|
|
|
|
await openFanoutSettings(page);
|
|
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
|
|
|
|
// Click Edit on our apprise config
|
|
const row = fanoutHeader(page, 'API Apprise');
|
|
await expect(row).toBeVisible();
|
|
await row.getByRole('button', { name: 'Edit' }).click();
|
|
|
|
// Verify the URLs textarea has our content
|
|
const urlsTextarea = page.locator('#fanout-apprise-urls');
|
|
await expect(urlsTextarea).toHaveValue(new RegExp(appriseUrl.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
await expect(urlsTextarea).toHaveValue(/slack:\/\/token_a/);
|
|
|
|
// Verify checkboxes reflect our config (both unchecked)
|
|
const preserveCheckbox = page
|
|
.getByText('Preserve identity on Discord')
|
|
.locator('xpath=ancestor::label[1]')
|
|
.locator('input[type="checkbox"]');
|
|
await expect(preserveCheckbox).not.toBeChecked();
|
|
|
|
const pathCheckbox = page
|
|
.getByText('Include routing path in notifications')
|
|
.locator('xpath=ancestor::label[1]')
|
|
.locator('input[type="checkbox"]');
|
|
await expect(pathCheckbox).not.toBeChecked();
|
|
|
|
// Go back
|
|
page.once('dialog', (dialog) => dialog.accept());
|
|
await page.getByText('← Back to list').click();
|
|
await expect(row).toBeVisible();
|
|
});
|
|
|
|
test('apprise shows scope selector', async ({ page }) => {
|
|
const apprise = await createFanoutConfig({
|
|
type: 'apprise',
|
|
name: 'Scope Apprise',
|
|
config: { urls: appriseUrl },
|
|
});
|
|
createdAppriseId = apprise.id;
|
|
|
|
await openFanoutSettings(page);
|
|
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
|
|
|
|
const row = fanoutHeader(page, 'Scope Apprise');
|
|
await expect(row).toBeVisible();
|
|
await row.getByRole('button', { name: 'Edit' }).click();
|
|
|
|
// Verify scope selector is present
|
|
await expect(page.getByText('Message Scope')).toBeVisible();
|
|
await expect(page.getByText('All messages')).toBeVisible();
|
|
|
|
// Select "All except listed" mode
|
|
await page.getByText('All except listed channels/contacts').click();
|
|
|
|
// Should show channel and contact lists with exclude label
|
|
await expect(page.getByText('Channels (exclude)')).toBeVisible();
|
|
|
|
// Go back
|
|
page.once('dialog', (dialog) => dialog.accept());
|
|
await page.getByText('← Back to list').click();
|
|
await expect(row).toBeVisible();
|
|
});
|
|
|
|
test('apprise disabled config shows disabled status and can be enabled via save button', async ({
|
|
page,
|
|
}) => {
|
|
const apprise = await createFanoutConfig({
|
|
type: 'apprise',
|
|
name: 'Disabled Apprise',
|
|
config: { urls: appriseUrl },
|
|
enabled: false,
|
|
});
|
|
createdAppriseId = apprise.id;
|
|
|
|
await openFanoutSettings(page);
|
|
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
|
|
|
|
// Should show "Disabled" status text
|
|
const row = fanoutHeader(page, 'Disabled Apprise');
|
|
await expect(row).toContainText('Disabled');
|
|
|
|
// Edit it
|
|
await expect(row).toBeVisible();
|
|
await row.getByRole('button', { name: 'Edit' }).click();
|
|
|
|
// Save as enabled
|
|
await page.getByRole('button', { name: /Save as Enabled/i }).click();
|
|
await expect(page.getByText('Integration saved and enabled')).toBeVisible();
|
|
|
|
// Verify it's now enabled via API
|
|
const configs = await getFanoutConfigs();
|
|
const updated = configs.find((c) => c.id === apprise.id);
|
|
expect(updated?.enabled).toBe(true);
|
|
});
|
|
|
|
test('delete apprise via UI', async ({ page }) => {
|
|
const apprise = await createFanoutConfig({
|
|
type: 'apprise',
|
|
name: 'Delete Me Apprise',
|
|
config: { urls: appriseUrl },
|
|
});
|
|
createdAppriseId = apprise.id;
|
|
|
|
await openFanoutSettings(page);
|
|
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
|
|
|
|
const row = fanoutHeader(page, 'Delete Me Apprise');
|
|
await expect(row).toBeVisible();
|
|
await row.getByRole('button', { name: 'Edit' }).click();
|
|
|
|
// Accept the confirmation dialog
|
|
page.once('dialog', (dialog) => dialog.accept());
|
|
|
|
await page.getByRole('button', { name: 'Delete' }).click();
|
|
|
|
// Should be back on list, apprise gone
|
|
await expect(row).not.toBeVisible();
|
|
createdAppriseId = null;
|
|
});
|
|
});
|