mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-05-14 21:36:03 +02:00
132 lines
4.5 KiB
TypeScript
132 lines
4.5 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import {
|
|
createContact,
|
|
deleteContact,
|
|
getContactByKey,
|
|
getMessages,
|
|
setContactRoutingOverride,
|
|
} from '../helpers/api';
|
|
import {
|
|
E2E_PARTNER_RADIO_PUBKEY,
|
|
E2E_PARTNER_RADIO_NAME,
|
|
} from '../helpers/env';
|
|
|
|
const PARTNER_RADIO_NOTICE =
|
|
`Partner-radio hardware test. Requires a nearby node "${E2E_PARTNER_RADIO_NAME}" ` +
|
|
`(${E2E_PARTNER_RADIO_PUBKEY.slice(0, 12)}...) that will ACK DMs from this radio. ` +
|
|
`Set E2E_USE_PARTNER_RADIO_FOR_DM_ACK_TEST=1 to run, and override ` +
|
|
`E2E_PARTNER_RADIO_PUBKEY / E2E_PARTNER_RADIO_NAME to match your hardware.`;
|
|
|
|
function escapeRegex(value: string): string {
|
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
}
|
|
|
|
test.describe('Partner-radio direct-route learning via DM ACK', () => {
|
|
test('zero-hop adverts then DM ACK learns a direct route', { tag: '@partner-radio' }, async ({
|
|
page,
|
|
}, testInfo) => {
|
|
testInfo.annotations.push({ type: 'notice', description: PARTNER_RADIO_NOTICE });
|
|
test.setTimeout(180_000);
|
|
|
|
try {
|
|
await deleteContact(E2E_PARTNER_RADIO_PUBKEY);
|
|
} catch {
|
|
// Best-effort reset; the contact may not exist yet in the temp E2E DB.
|
|
}
|
|
|
|
await createContact(E2E_PARTNER_RADIO_PUBKEY, E2E_PARTNER_RADIO_NAME);
|
|
await setContactRoutingOverride(E2E_PARTNER_RADIO_PUBKEY, '');
|
|
|
|
await expect
|
|
.poll(
|
|
async () => {
|
|
const contact = await getContactByKey(E2E_PARTNER_RADIO_PUBKEY);
|
|
return contact?.direct_path_len ?? null;
|
|
},
|
|
{
|
|
timeout: 10_000,
|
|
message: 'Waiting for recreated partner contact to start in flood mode',
|
|
}
|
|
)
|
|
.toBe(-1);
|
|
|
|
await page.goto('/#settings/radio');
|
|
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
|
|
|
|
const zeroHopButton = page.getByRole('button', { name: 'Send Zero-Hop Advertisement' });
|
|
await expect(zeroHopButton).toBeVisible();
|
|
|
|
await zeroHopButton.click();
|
|
await expect(page.getByText('Zero-hop advertisement sent')).toBeVisible({ timeout: 15_000 });
|
|
|
|
await page.waitForTimeout(5_000);
|
|
|
|
await zeroHopButton.click();
|
|
await expect(page.getByText('Zero-hop advertisement sent')).toBeVisible({ timeout: 15_000 });
|
|
|
|
await page.getByRole('button', { name: /Back to Chat/i }).click();
|
|
await expect(page.getByRole('button', { name: /Back to Chat/i })).toBeHidden({
|
|
timeout: 15_000,
|
|
});
|
|
|
|
const searchInput = page.getByLabel('Search conversations');
|
|
await searchInput.fill(E2E_PARTNER_RADIO_PUBKEY.slice(0, 12));
|
|
await expect(page.getByText(E2E_PARTNER_RADIO_NAME, { exact: true })).toBeVisible({
|
|
timeout: 15_000,
|
|
});
|
|
await page.getByText(E2E_PARTNER_RADIO_NAME, { exact: true }).click();
|
|
await expect
|
|
.poll(() => page.url(), {
|
|
timeout: 15_000,
|
|
message: 'Waiting for partner contact conversation route to load',
|
|
})
|
|
.toContain(`#contact/${encodeURIComponent(E2E_PARTNER_RADIO_PUBKEY)}`);
|
|
await expect(
|
|
page.getByPlaceholder(new RegExp(`message\\s+${escapeRegex(E2E_PARTNER_RADIO_NAME)}`, 'i'))
|
|
).toBeVisible({ timeout: 15_000 });
|
|
|
|
const text = `dm-ack-route-test-${Date.now()}`;
|
|
const input = page.getByPlaceholder(/message/i);
|
|
await input.fill(text);
|
|
await page.getByRole('button', { name: 'Send', exact: true }).click();
|
|
await expect(page.getByText(text)).toBeVisible({ timeout: 15_000 });
|
|
|
|
await expect
|
|
.poll(
|
|
async () => {
|
|
const messages = await getMessages({
|
|
type: 'PRIV',
|
|
conversation_key: E2E_PARTNER_RADIO_PUBKEY,
|
|
limit: 25,
|
|
});
|
|
const match = messages.find((message) => message.outgoing && message.text === text);
|
|
return match?.acked ?? 0;
|
|
},
|
|
{
|
|
timeout: 90_000,
|
|
message: 'Waiting for partner radio DM ACK',
|
|
}
|
|
)
|
|
.toBeGreaterThan(0);
|
|
|
|
await expect
|
|
.poll(
|
|
async () => {
|
|
const contact = await getContactByKey(E2E_PARTNER_RADIO_PUBKEY);
|
|
return contact?.direct_path_len ?? null;
|
|
},
|
|
{
|
|
timeout: 90_000,
|
|
message: 'Waiting for partner radio route to update from flood to direct',
|
|
}
|
|
)
|
|
.toBe(0);
|
|
|
|
const learnedContact = await getContactByKey(E2E_PARTNER_RADIO_PUBKEY);
|
|
expect(learnedContact?.direct_path ?? '').toBe('');
|
|
|
|
await page.locator('[title="View contact info"]').click();
|
|
await expect(page.getByLabel('Contact Info')).toBeVisible({ timeout: 15_000 });
|
|
});
|
|
});
|